fuzzgen: Add SIMD instructions supported by the interpreter (#5971)

* fuzzgen: Add some SIMD instructions

* fuzzgen: Remove `scalar_to_vector`

Broken in the interpreter #5911

* fuzzgen: Remove SIMD bitcasts

Broken in the interpreter #5915

* fuzzgen: Fix insert lane

* fuzzgen: Remove debug code

* fuzzgen: Remove vall_true

This is broken in the interpreter #5916

* fuzzgen: Disable a few more ops

* fuzzgen: Remove `iadd_pairwise.i64x2`

Turns out it doesen't exist

* fuzzgen: Remove scalar `sqmul_round_sat`

#5923

* fuzzgen: Disable aligned loads to SIMD values

* fuzzgen: Address Review Feedback

Co-Authored-By: Jamey Sharp <jsharp@fastly.com>

* fuzzgen: Rework `cmp` exclusion rules

Co-Authored-By: Jamey Sharp <jsharp@fastly.com>

---------

Co-authored-by: Jamey Sharp <jsharp@fastly.com>
This commit is contained in:
Afonso Bordado
2023-03-11 12:20:21 +00:00
committed by GitHub
parent af7ef8df9a
commit 2386eee56b

View File

@@ -6,9 +6,10 @@ use cranelift::codegen::data_value::DataValue;
use cranelift::codegen::ir::immediates::Offset32; use cranelift::codegen::ir::immediates::Offset32;
use cranelift::codegen::ir::instructions::InstructionFormat; use cranelift::codegen::ir::instructions::InstructionFormat;
use cranelift::codegen::ir::stackslot::StackSize; use cranelift::codegen::ir::stackslot::StackSize;
use cranelift::codegen::ir::{ use cranelift::codegen::ir::{
types::*, AtomicRmwOp, Block, ExternalName, FuncRef, Function, LibCall, Opcode, Signature, types::*, AtomicRmwOp, Block, ConstantData, ExternalName, FuncRef, Function, LibCall, Opcode,
StackSlot, Type, UserExternalName, UserFuncName, Value, Signature, StackSlot, Type, UserExternalName, UserFuncName, Value,
}; };
use cranelift::codegen::isa::CallConv; use cranelift::codegen::isa::CallConv;
use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Switch, Variable}; use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Switch, Variable};
@@ -36,10 +37,10 @@ fn insert_opcode(
vals.push(val); vals.push(val);
} }
// For pretty much every instruction the control type is the return type // Some opcodes require us to look at their input arguments to determine the
// except for Iconcat and Isplit which are *special* and the control type // controlling type. This is not the general case, but we can neatly check this
// is the input type. // using `requires_typevar_operand`.
let ctrl_type = if opcode == Opcode::Iconcat || opcode == Opcode::Isplit { let ctrl_type = if opcode.constraints().requires_typevar_operand() {
args.first() args.first()
} else { } else {
rets.first() rets.first()
@@ -139,26 +140,28 @@ fn insert_cmp(
let res = if opcode == Opcode::Fcmp { let res = if opcode == Opcode::Fcmp {
let cc = *fgen.u.choose(FloatCC::all())?; let cc = *fgen.u.choose(FloatCC::all())?;
// Some FloatCC's are not implemented on AArch64, see:
// https://github.com/bytecodealliance/wasmtime/issues/4850
// We filter out condition codes that aren't supported by the target at // We filter out condition codes that aren't supported by the target at
// this point after randomly choosing one, instead of randomly choosing a // this point after randomly choosing one, instead of randomly choosing a
// supported one, to avoid invalidating the corpus when these get implemented. // supported one, to avoid invalidating the corpus when these get implemented.
if matches!(fgen.target_triple.architecture, Architecture::Aarch64(_)) let unimplemented_cc = match (fgen.target_triple.architecture, cc) {
&& ![ // Some FloatCC's are not implemented on AArch64, see:
FloatCC::Ordered, // https://github.com/bytecodealliance/wasmtime/issues/4850
FloatCC::Unordered, (Architecture::Aarch64(_), FloatCC::OrderedNotEqual) => true,
FloatCC::Equal, (Architecture::Aarch64(_), FloatCC::UnorderedOrEqual) => true,
FloatCC::NotEqual, (Architecture::Aarch64(_), FloatCC::UnorderedOrLessThan) => true,
FloatCC::LessThan, (Architecture::Aarch64(_), FloatCC::UnorderedOrLessThanOrEqual) => true,
FloatCC::LessThanOrEqual, (Architecture::Aarch64(_), FloatCC::UnorderedOrGreaterThan) => true,
FloatCC::GreaterThan, (Architecture::Aarch64(_), FloatCC::UnorderedOrGreaterThanOrEqual) => true,
FloatCC::GreaterThanOrEqual,
] // These are not implemented on x86_64, for vectors.
.contains(&cc) (Architecture::X86_64, FloatCC::UnorderedOrEqual | FloatCC::OrderedNotEqual) => {
{ args[0].is_vector()
return Err(arbitrary::Error::IncorrectFormat.into()); }
_ => false,
}; };
if unimplemented_cc {
return Err(arbitrary::Error::IncorrectFormat.into());
}
builder.ins().fcmp(cc, lhs, rhs) builder.ins().fcmp(cc, lhs, rhs)
} else { } else {
@@ -323,6 +326,65 @@ fn insert_atomic_cas(
Ok(()) Ok(())
} }
fn insert_shuffle(
fgen: &mut FunctionGenerator,
builder: &mut FunctionBuilder,
opcode: Opcode,
_: &'static [Type],
rets: &'static [Type],
) -> Result<()> {
let ctrl_type = *rets.first().unwrap();
let lhs = builder.use_var(fgen.get_variable_of_type(ctrl_type)?);
let rhs = builder.use_var(fgen.get_variable_of_type(ctrl_type)?);
let mask = {
let lanes = fgen.u.arbitrary::<[u8; 16]>()?;
let lanes = ConstantData::from(lanes.as_ref());
builder.func.dfg.immediates.push(lanes)
};
// This function is called for any `InstructionFormat::Shuffle`. Which today is just
// `shuffle`, but lets assert that, just to be sure we don't accidentally insert
// something else.
assert_eq!(opcode, Opcode::Shuffle);
let res = builder.ins().shuffle(lhs, rhs, mask);
let target_var = fgen.get_variable_of_type(ctrl_type)?;
builder.def_var(target_var, res);
Ok(())
}
fn insert_ins_ext_lane(
fgen: &mut FunctionGenerator,
builder: &mut FunctionBuilder,
opcode: Opcode,
args: &'static [Type],
rets: &'static [Type],
) -> Result<()> {
let vector_type = *args.first().unwrap();
let ret_type = *rets.first().unwrap();
let lhs = builder.use_var(fgen.get_variable_of_type(vector_type)?);
let max_lane = (vector_type.lane_count() as u8) - 1;
let lane = fgen.u.int_in_range(0..=max_lane)?;
let res = match opcode {
Opcode::Insertlane => {
let rhs = builder.use_var(fgen.get_variable_of_type(args[1])?);
builder.ins().insertlane(lhs, rhs, lane)
}
Opcode::Extractlane => builder.ins().extractlane(lhs, lane),
_ => todo!(),
};
let target_var = fgen.get_variable_of_type(ret_type)?;
builder.def_var(target_var, res);
Ok(())
}
type OpcodeInserter = fn( type OpcodeInserter = fn(
fgen: &mut FunctionGenerator, fgen: &mut FunctionGenerator,
builder: &mut FunctionBuilder, builder: &mut FunctionBuilder,
@@ -433,6 +495,8 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
(Opcode::FcvtToUint, &[F64], &[I8]), (Opcode::FcvtToUint, &[F64], &[I8]),
(Opcode::FcvtToUint, &[F64], &[I16]), (Opcode::FcvtToUint, &[F64], &[I16]),
(Opcode::FcvtToUint, &[F64], &[I128]), (Opcode::FcvtToUint, &[F64], &[I128]),
(Opcode::FcvtToUint, &[F32X4], &[I32X4]),
(Opcode::FcvtToUint, &[F64X2], &[I64X2]),
// https://github.com/bytecodealliance/wasmtime/issues/4897 // https://github.com/bytecodealliance/wasmtime/issues/4897
// https://github.com/bytecodealliance/wasmtime/issues/4899 // https://github.com/bytecodealliance/wasmtime/issues/4899
(Opcode::FcvtToUintSat, &[F32], &[I8]), (Opcode::FcvtToUintSat, &[F32], &[I8]),
@@ -441,6 +505,7 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
(Opcode::FcvtToUintSat, &[F64], &[I8]), (Opcode::FcvtToUintSat, &[F64], &[I8]),
(Opcode::FcvtToUintSat, &[F64], &[I16]), (Opcode::FcvtToUintSat, &[F64], &[I16]),
(Opcode::FcvtToUintSat, &[F64], &[I128]), (Opcode::FcvtToUintSat, &[F64], &[I128]),
(Opcode::FcvtToUintSat, &[F64X2], &[I64X2]),
// https://github.com/bytecodealliance/wasmtime/issues/4897 // https://github.com/bytecodealliance/wasmtime/issues/4897
// https://github.com/bytecodealliance/wasmtime/issues/4899 // https://github.com/bytecodealliance/wasmtime/issues/4899
(Opcode::FcvtToSint, &[F32], &[I8]), (Opcode::FcvtToSint, &[F32], &[I8]),
@@ -449,6 +514,8 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
(Opcode::FcvtToSint, &[F64], &[I8]), (Opcode::FcvtToSint, &[F64], &[I8]),
(Opcode::FcvtToSint, &[F64], &[I16]), (Opcode::FcvtToSint, &[F64], &[I16]),
(Opcode::FcvtToSint, &[F64], &[I128]), (Opcode::FcvtToSint, &[F64], &[I128]),
(Opcode::FcvtToSint, &[F32X4], &[I32X4]),
(Opcode::FcvtToSint, &[F64X2], &[I64X2]),
// https://github.com/bytecodealliance/wasmtime/issues/4897 // https://github.com/bytecodealliance/wasmtime/issues/4897
// https://github.com/bytecodealliance/wasmtime/issues/4899 // https://github.com/bytecodealliance/wasmtime/issues/4899
(Opcode::FcvtToSintSat, &[F32], &[I8]), (Opcode::FcvtToSintSat, &[F32], &[I8]),
@@ -457,12 +524,73 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
(Opcode::FcvtToSintSat, &[F64], &[I8]), (Opcode::FcvtToSintSat, &[F64], &[I8]),
(Opcode::FcvtToSintSat, &[F64], &[I16]), (Opcode::FcvtToSintSat, &[F64], &[I16]),
(Opcode::FcvtToSintSat, &[F64], &[I128]), (Opcode::FcvtToSintSat, &[F64], &[I128]),
(Opcode::FcvtToSintSat, &[F64X2], &[I64X2]),
// https://github.com/bytecodealliance/wasmtime/issues/4900 // https://github.com/bytecodealliance/wasmtime/issues/4900
(Opcode::FcvtFromUint, &[I128], &[F32]), (Opcode::FcvtFromUint, &[I128], &[F32]),
(Opcode::FcvtFromUint, &[I128], &[F64]), (Opcode::FcvtFromUint, &[I128], &[F64]),
// This has a lowering, but only when preceded by `uwiden_low`.
(Opcode::FcvtFromUint, &[I64X2], &[F64X2]),
// https://github.com/bytecodealliance/wasmtime/issues/4900 // https://github.com/bytecodealliance/wasmtime/issues/4900
(Opcode::FcvtFromSint, &[I128], &[F32]), (Opcode::FcvtFromSint, &[I128], &[F32]),
(Opcode::FcvtFromSint, &[I128], &[F64]), (Opcode::FcvtFromSint, &[I128], &[F64]),
(Opcode::FcvtFromSint, &[I64X2], &[F64X2]),
(Opcode::Bmask, &[I8X16]),
(Opcode::Bmask, &[I16X8]),
(Opcode::Bmask, &[I32X4]),
(Opcode::Bmask, &[I64X2]),
(Opcode::Umulhi, &[I8X16, I8X16]),
(Opcode::Umulhi, &[I16X8, I16X8]),
(Opcode::Umulhi, &[I32X4, I32X4]),
(Opcode::Umulhi, &[I64X2, I64X2]),
(Opcode::Smulhi, &[I8X16, I8X16]),
(Opcode::Smulhi, &[I16X8, I16X8]),
(Opcode::Smulhi, &[I32X4, I32X4]),
(Opcode::Smulhi, &[I64X2, I64X2]),
(Opcode::UaddSat, &[I32X4, I32X4]),
(Opcode::UaddSat, &[I64X2, I64X2]),
(Opcode::SaddSat, &[I32X4, I32X4]),
(Opcode::SaddSat, &[I64X2, I64X2]),
(Opcode::UsubSat, &[I32X4, I32X4]),
(Opcode::UsubSat, &[I64X2, I64X2]),
(Opcode::SsubSat, &[I32X4, I32X4]),
(Opcode::SsubSat, &[I64X2, I64X2]),
(Opcode::Fcopysign, &[F32X4, F32X4]),
(Opcode::Fcopysign, &[F64X2, F64X2]),
(Opcode::Popcnt, &[I8X16]),
(Opcode::Popcnt, &[I16X8]),
(Opcode::Popcnt, &[I32X4]),
(Opcode::Popcnt, &[I64X2]),
(Opcode::Umax, &[I64X2, I64X2]),
(Opcode::Smax, &[I64X2, I64X2]),
(Opcode::Umin, &[I64X2, I64X2]),
(Opcode::Smin, &[I64X2, I64X2]),
(Opcode::Bitcast, &[I128], &[_]),
(Opcode::Bitcast, &[_], &[I128]),
(Opcode::Uunarrow),
(Opcode::Snarrow, &[I64X2, I64X2]),
(Opcode::Unarrow, &[I64X2, I64X2]),
(Opcode::SqmulRoundSat, &[I32X4, I32X4]),
// This Icmp is not implemented: #5529
(Opcode::Icmp, &[I64X2, I64X2]),
// IaddPairwise is implemented, but only for some types, and with some preceding ops.
(Opcode::IaddPairwise),
// Nothing wrong with this select. But we have an isle rule that can optimize it
// into a `min`/`max` instructions, which we don't have implemented yet.
(Opcode::Select, &[_, I128, I128]),
// These stack accesses can cause segfaults if they are merged into an SSE instruction.
// See: #5922
(Opcode::StackStore, &[I8X16], &[]),
(Opcode::StackStore, &[I16X8], &[]),
(Opcode::StackStore, &[I32X4], &[]),
(Opcode::StackStore, &[I64X2], &[]),
(Opcode::StackStore, &[F32X4], &[]),
(Opcode::StackStore, &[F64X2], &[]),
(Opcode::StackLoad, &[], &[I8X16]),
(Opcode::StackLoad, &[], &[I16X8]),
(Opcode::StackLoad, &[], &[I32X4]),
(Opcode::StackLoad, &[], &[I64X2]),
(Opcode::StackLoad, &[], &[F32X4]),
(Opcode::StackLoad, &[], &[F64X2]),
) )
} }
@@ -528,6 +656,24 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
// https://github.com/bytecodealliance/wasmtime/issues/4933 // https://github.com/bytecodealliance/wasmtime/issues/4933
(Opcode::FcvtFromSint, &[I128], &[F32]), (Opcode::FcvtFromSint, &[I128], &[F32]),
(Opcode::FcvtFromSint, &[I128], &[F64]), (Opcode::FcvtFromSint, &[I128], &[F64]),
(Opcode::Bmask, &[I8X16]),
(Opcode::Bmask, &[I16X8]),
(Opcode::Bmask, &[I32X4]),
(Opcode::Bmask, &[I64X2]),
(Opcode::Umulhi, &[I8X16, I8X16]),
(Opcode::Umulhi, &[I16X8, I16X8]),
(Opcode::Umulhi, &[I32X4, I32X4]),
(Opcode::Umulhi, &[I64X2, I64X2]),
(Opcode::Smulhi, &[I8X16, I8X16]),
(Opcode::Smulhi, &[I16X8, I16X8]),
(Opcode::Smulhi, &[I32X4, I32X4]),
(Opcode::Smulhi, &[I64X2, I64X2]),
(Opcode::Popcnt, &[I16X8]),
(Opcode::Popcnt, &[I32X4]),
(Opcode::Popcnt, &[I64X2]),
// Nothing wrong with this select. But we have an isle rule that can optimize it
// into a `min`/`max` instructions, which we don't have implemented yet.
(Opcode::Select, &[I8, I128, I128]),
) )
} }
@@ -564,6 +710,12 @@ fn valid_for_target(triple: &Triple, op: Opcode, args: &[Type], rets: &[Type]) -
(Opcode::FcvtFromUint, &[I128], &[F64]), (Opcode::FcvtFromUint, &[I128], &[F64]),
(Opcode::FcvtFromSint, &[I128], &[F32]), (Opcode::FcvtFromSint, &[I128], &[F32]),
(Opcode::FcvtFromSint, &[I128], &[F64]), (Opcode::FcvtFromSint, &[I128], &[F64]),
(Opcode::Bmask, &[I8X16]),
(Opcode::Bmask, &[I16X8]),
(Opcode::Bmask, &[I32X4]),
(Opcode::Bmask, &[I64X2]),
(Opcode::SsubSat, &[I64X2, I64X2]),
(Opcode::SaddSat, &[I64X2, I64X2]),
) )
} }
@@ -687,12 +839,32 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::IaddCout, &[I32, I32], &[I32, I8]), (Opcode::IaddCout, &[I32, I32], &[I32, I8]),
(Opcode::IaddCout, &[I64, I64], &[I64, I8]), (Opcode::IaddCout, &[I64, I64], &[I64, I8]),
(Opcode::IaddCout, &[I128, I128], &[I128, I8]), (Opcode::IaddCout, &[I128, I128], &[I128, I8]),
// UaddSat
(Opcode::UaddSat, &[I8X16, I8X16], &[I8X16]),
(Opcode::UaddSat, &[I16X8, I16X8], &[I16X8]),
(Opcode::UaddSat, &[I32X4, I32X4], &[I32X4]),
(Opcode::UaddSat, &[I64X2, I64X2], &[I64X2]),
// SaddSat
(Opcode::SaddSat, &[I8X16, I8X16], &[I8X16]),
(Opcode::SaddSat, &[I16X8, I16X8], &[I16X8]),
(Opcode::SaddSat, &[I32X4, I32X4], &[I32X4]),
(Opcode::SaddSat, &[I64X2, I64X2], &[I64X2]),
// Isub // Isub
(Opcode::Isub, &[I8, I8], &[I8]), (Opcode::Isub, &[I8, I8], &[I8]),
(Opcode::Isub, &[I16, I16], &[I16]), (Opcode::Isub, &[I16, I16], &[I16]),
(Opcode::Isub, &[I32, I32], &[I32]), (Opcode::Isub, &[I32, I32], &[I32]),
(Opcode::Isub, &[I64, I64], &[I64]), (Opcode::Isub, &[I64, I64], &[I64]),
(Opcode::Isub, &[I128, I128], &[I128]), (Opcode::Isub, &[I128, I128], &[I128]),
// UsubSat
(Opcode::UsubSat, &[I8X16, I8X16], &[I8X16]),
(Opcode::UsubSat, &[I16X8, I16X8], &[I16X8]),
(Opcode::UsubSat, &[I32X4, I32X4], &[I32X4]),
(Opcode::UsubSat, &[I64X2, I64X2], &[I64X2]),
// SsubSat
(Opcode::SsubSat, &[I8X16, I8X16], &[I8X16]),
(Opcode::SsubSat, &[I16X8, I16X8], &[I16X8]),
(Opcode::SsubSat, &[I32X4, I32X4], &[I32X4]),
(Opcode::SsubSat, &[I64X2, I64X2], &[I64X2]),
// Imul // Imul
(Opcode::Imul, &[I8, I8], &[I8]), (Opcode::Imul, &[I8, I8], &[I8]),
(Opcode::Imul, &[I16, I16], &[I16]), (Opcode::Imul, &[I16, I16], &[I16]),
@@ -704,11 +876,19 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::Smulhi, &[I16, I16], &[I16]), (Opcode::Smulhi, &[I16, I16], &[I16]),
(Opcode::Smulhi, &[I32, I32], &[I32]), (Opcode::Smulhi, &[I32, I32], &[I32]),
(Opcode::Smulhi, &[I64, I64], &[I64]), (Opcode::Smulhi, &[I64, I64], &[I64]),
(Opcode::Smulhi, &[I8X16, I8X16], &[I8X16]),
(Opcode::Smulhi, &[I16X8, I16X8], &[I16X8]),
(Opcode::Smulhi, &[I32X4, I32X4], &[I32X4]),
(Opcode::Smulhi, &[I64X2, I64X2], &[I64X2]),
// Umulhi // Umulhi
(Opcode::Umulhi, &[I8, I8], &[I8]), (Opcode::Umulhi, &[I8, I8], &[I8]),
(Opcode::Umulhi, &[I16, I16], &[I16]), (Opcode::Umulhi, &[I16, I16], &[I16]),
(Opcode::Umulhi, &[I32, I32], &[I32]), (Opcode::Umulhi, &[I32, I32], &[I32]),
(Opcode::Umulhi, &[I64, I64], &[I64]), (Opcode::Umulhi, &[I64, I64], &[I64]),
(Opcode::Umulhi, &[I8X16, I8X16], &[I8X16]),
(Opcode::Umulhi, &[I16X8, I16X8], &[I16X8]),
(Opcode::Umulhi, &[I32X4, I32X4], &[I32X4]),
(Opcode::Umulhi, &[I64X2, I64X2], &[I64X2]),
// Udiv // Udiv
(Opcode::Udiv, &[I8, I8], &[I8]), (Opcode::Udiv, &[I8, I8], &[I8]),
(Opcode::Udiv, &[I16, I16], &[I16]), (Opcode::Udiv, &[I16, I16], &[I16]),
@@ -755,24 +935,40 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::Smin, &[I32, I32], &[I32]), (Opcode::Smin, &[I32, I32], &[I32]),
(Opcode::Smin, &[I64, I64], &[I64]), (Opcode::Smin, &[I64, I64], &[I64]),
(Opcode::Smin, &[I128, I128], &[I128]), (Opcode::Smin, &[I128, I128], &[I128]),
(Opcode::Smin, &[I8X16, I8X16], &[I8X16]),
(Opcode::Smin, &[I16X8, I16X8], &[I16X8]),
(Opcode::Smin, &[I32X4, I32X4], &[I32X4]),
(Opcode::Smin, &[I64X2, I64X2], &[I64X2]),
// Umin // Umin
(Opcode::Umin, &[I8, I8], &[I8]), (Opcode::Umin, &[I8, I8], &[I8]),
(Opcode::Umin, &[I16, I16], &[I16]), (Opcode::Umin, &[I16, I16], &[I16]),
(Opcode::Umin, &[I32, I32], &[I32]), (Opcode::Umin, &[I32, I32], &[I32]),
(Opcode::Umin, &[I64, I64], &[I64]), (Opcode::Umin, &[I64, I64], &[I64]),
(Opcode::Umin, &[I128, I128], &[I128]), (Opcode::Umin, &[I128, I128], &[I128]),
(Opcode::Umin, &[I8X16, I8X16], &[I8X16]),
(Opcode::Umin, &[I16X8, I16X8], &[I16X8]),
(Opcode::Umin, &[I32X4, I32X4], &[I32X4]),
(Opcode::Umin, &[I64X2, I64X2], &[I64X2]),
// Smax // Smax
(Opcode::Smax, &[I8, I8], &[I8]), (Opcode::Smax, &[I8, I8], &[I8]),
(Opcode::Smax, &[I16, I16], &[I16]), (Opcode::Smax, &[I16, I16], &[I16]),
(Opcode::Smax, &[I32, I32], &[I32]), (Opcode::Smax, &[I32, I32], &[I32]),
(Opcode::Smax, &[I64, I64], &[I64]), (Opcode::Smax, &[I64, I64], &[I64]),
(Opcode::Smax, &[I128, I128], &[I128]), (Opcode::Smax, &[I128, I128], &[I128]),
(Opcode::Smax, &[I8X16, I8X16], &[I8X16]),
(Opcode::Smax, &[I16X8, I16X8], &[I16X8]),
(Opcode::Smax, &[I32X4, I32X4], &[I32X4]),
(Opcode::Smax, &[I64X2, I64X2], &[I64X2]),
// Umax // Umax
(Opcode::Umax, &[I8, I8], &[I8]), (Opcode::Umax, &[I8, I8], &[I8]),
(Opcode::Umax, &[I16, I16], &[I16]), (Opcode::Umax, &[I16, I16], &[I16]),
(Opcode::Umax, &[I32, I32], &[I32]), (Opcode::Umax, &[I32, I32], &[I32]),
(Opcode::Umax, &[I64, I64], &[I64]), (Opcode::Umax, &[I64, I64], &[I64]),
(Opcode::Umax, &[I128, I128], &[I128]), (Opcode::Umax, &[I128, I128], &[I128]),
(Opcode::Umax, &[I8X16, I8X16], &[I8X16]),
(Opcode::Umax, &[I16X8, I16X8], &[I16X8]),
(Opcode::Umax, &[I32X4, I32X4], &[I32X4]),
(Opcode::Umax, &[I64X2, I64X2], &[I64X2]),
// Rotr // Rotr
(Opcode::Rotr, &[I8, I8], &[I8]), (Opcode::Rotr, &[I8, I8], &[I8]),
(Opcode::Rotr, &[I8, I16], &[I8]), (Opcode::Rotr, &[I8, I16], &[I8]),
@@ -1026,6 +1222,10 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::Popcnt, &[I32], &[I32]), (Opcode::Popcnt, &[I32], &[I32]),
(Opcode::Popcnt, &[I64], &[I64]), (Opcode::Popcnt, &[I64], &[I64]),
(Opcode::Popcnt, &[I128], &[I128]), (Opcode::Popcnt, &[I128], &[I128]),
(Opcode::Popcnt, &[I8X16], &[I8X16]),
(Opcode::Popcnt, &[I16X8], &[I16X8]),
(Opcode::Popcnt, &[I32X4], &[I32X4]),
(Opcode::Popcnt, &[I64X2], &[I64X2]),
// Bmask // Bmask
(Opcode::Bmask, &[I8], &[I8]), (Opcode::Bmask, &[I8], &[I8]),
(Opcode::Bmask, &[I16], &[I8]), (Opcode::Bmask, &[I16], &[I8]),
@@ -1052,6 +1252,10 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::Bmask, &[I32], &[I128]), (Opcode::Bmask, &[I32], &[I128]),
(Opcode::Bmask, &[I64], &[I128]), (Opcode::Bmask, &[I64], &[I128]),
(Opcode::Bmask, &[I128], &[I128]), (Opcode::Bmask, &[I128], &[I128]),
(Opcode::Bmask, &[I8X16], &[I8X16]),
(Opcode::Bmask, &[I16X8], &[I16X8]),
(Opcode::Bmask, &[I32X4], &[I32X4]),
(Opcode::Bmask, &[I64X2], &[I64X2]),
// Bswap // Bswap
(Opcode::Bswap, &[I16], &[I16]), (Opcode::Bswap, &[I16], &[I16]),
(Opcode::Bswap, &[I32], &[I32]), (Opcode::Bswap, &[I32], &[I32]),
@@ -1142,6 +1346,8 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
// Fcopysign // Fcopysign
(Opcode::Fcopysign, &[F32, F32], &[F32]), (Opcode::Fcopysign, &[F32, F32], &[F32]),
(Opcode::Fcopysign, &[F64, F64], &[F64]), (Opcode::Fcopysign, &[F64, F64], &[F64]),
(Opcode::Fcopysign, &[F32X4, F32X4], &[F32X4]),
(Opcode::Fcopysign, &[F64X2, F64X2], &[F64X2]),
// Fma // Fma
(Opcode::Fma, &[F32, F32, F32], &[F32]), (Opcode::Fma, &[F32, F32, F32], &[F32]),
(Opcode::Fma, &[F64, F64, F64], &[F64]), (Opcode::Fma, &[F64, F64, F64], &[F64]),
@@ -1192,6 +1398,8 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::FcvtToUintSat, &[F64], &[I32]), (Opcode::FcvtToUintSat, &[F64], &[I32]),
(Opcode::FcvtToUintSat, &[F64], &[I64]), (Opcode::FcvtToUintSat, &[F64], &[I64]),
(Opcode::FcvtToUintSat, &[F64], &[I128]), (Opcode::FcvtToUintSat, &[F64], &[I128]),
(Opcode::FcvtToUintSat, &[F32X4], &[I32X4]),
(Opcode::FcvtToUintSat, &[F64X2], &[I64X2]),
// FcvtToSint // FcvtToSint
(Opcode::FcvtToSint, &[F32], &[I8]), (Opcode::FcvtToSint, &[F32], &[I8]),
(Opcode::FcvtToSint, &[F32], &[I16]), (Opcode::FcvtToSint, &[F32], &[I16]),
@@ -1214,6 +1422,8 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::FcvtToSintSat, &[F64], &[I32]), (Opcode::FcvtToSintSat, &[F64], &[I32]),
(Opcode::FcvtToSintSat, &[F64], &[I64]), (Opcode::FcvtToSintSat, &[F64], &[I64]),
(Opcode::FcvtToSintSat, &[F64], &[I128]), (Opcode::FcvtToSintSat, &[F64], &[I128]),
(Opcode::FcvtToSintSat, &[F32X4], &[I32X4]),
(Opcode::FcvtToSintSat, &[F64X2], &[I64X2]),
// FcvtFromUint // FcvtFromUint
(Opcode::FcvtFromUint, &[I8], &[F32]), (Opcode::FcvtFromUint, &[I8], &[F32]),
(Opcode::FcvtFromUint, &[I16], &[F32]), (Opcode::FcvtFromUint, &[I16], &[F32]),
@@ -1225,6 +1435,8 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::FcvtFromUint, &[I32], &[F64]), (Opcode::FcvtFromUint, &[I32], &[F64]),
(Opcode::FcvtFromUint, &[I64], &[F64]), (Opcode::FcvtFromUint, &[I64], &[F64]),
(Opcode::FcvtFromUint, &[I128], &[F64]), (Opcode::FcvtFromUint, &[I128], &[F64]),
(Opcode::FcvtFromUint, &[I32X4], &[F32X4]),
(Opcode::FcvtFromUint, &[I64X2], &[F64X2]),
// FcvtFromSint // FcvtFromSint
(Opcode::FcvtFromSint, &[I8], &[F32]), (Opcode::FcvtFromSint, &[I8], &[F32]),
(Opcode::FcvtFromSint, &[I16], &[F32]), (Opcode::FcvtFromSint, &[I16], &[F32]),
@@ -1236,15 +1448,29 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::FcvtFromSint, &[I32], &[F64]), (Opcode::FcvtFromSint, &[I32], &[F64]),
(Opcode::FcvtFromSint, &[I64], &[F64]), (Opcode::FcvtFromSint, &[I64], &[F64]),
(Opcode::FcvtFromSint, &[I128], &[F64]), (Opcode::FcvtFromSint, &[I128], &[F64]),
(Opcode::FcvtFromSint, &[I32X4], &[F32X4]),
(Opcode::FcvtFromSint, &[I64X2], &[F64X2]),
// FcvtLowFromSint
(Opcode::FcvtLowFromSint, &[I32X4], &[F64X2]),
// FvpromoteLow
(Opcode::FvpromoteLow, &[F32X4], &[F64X2]),
// Fvdemote
(Opcode::Fvdemote, &[F64X2], &[F32X4]),
// Fcmp // Fcmp
(Opcode::Fcmp, &[F32, F32], &[I8]), (Opcode::Fcmp, &[F32, F32], &[I8]),
(Opcode::Fcmp, &[F64, F64], &[I8]), (Opcode::Fcmp, &[F64, F64], &[I8]),
(Opcode::Fcmp, &[F32X4, F32X4], &[I32X4]),
(Opcode::Fcmp, &[F64X2, F64X2], &[I64X2]),
// Icmp // Icmp
(Opcode::Icmp, &[I8, I8], &[I8]), (Opcode::Icmp, &[I8, I8], &[I8]),
(Opcode::Icmp, &[I16, I16], &[I8]), (Opcode::Icmp, &[I16, I16], &[I8]),
(Opcode::Icmp, &[I32, I32], &[I8]), (Opcode::Icmp, &[I32, I32], &[I8]),
(Opcode::Icmp, &[I64, I64], &[I8]), (Opcode::Icmp, &[I64, I64], &[I8]),
(Opcode::Icmp, &[I128, I128], &[I8]), (Opcode::Icmp, &[I128, I128], &[I8]),
(Opcode::Icmp, &[I8X16, I8X16], &[I8X16]),
(Opcode::Icmp, &[I16X8, I16X8], &[I16X8]),
(Opcode::Icmp, &[I32X4, I32X4], &[I32X4]),
(Opcode::Icmp, &[I64X2, I64X2], &[I64X2]),
// Fence // Fence
(Opcode::Fence, &[], &[]), (Opcode::Fence, &[], &[]),
// Stack Access // Stack Access
@@ -1253,11 +1479,27 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::StackStore, &[I32], &[]), (Opcode::StackStore, &[I32], &[]),
(Opcode::StackStore, &[I64], &[]), (Opcode::StackStore, &[I64], &[]),
(Opcode::StackStore, &[I128], &[]), (Opcode::StackStore, &[I128], &[]),
(Opcode::StackStore, &[F32], &[]),
(Opcode::StackStore, &[F64], &[]),
(Opcode::StackStore, &[I8X16], &[]),
(Opcode::StackStore, &[I16X8], &[]),
(Opcode::StackStore, &[I32X4], &[]),
(Opcode::StackStore, &[I64X2], &[]),
(Opcode::StackStore, &[F32X4], &[]),
(Opcode::StackStore, &[F64X2], &[]),
(Opcode::StackLoad, &[], &[I8]), (Opcode::StackLoad, &[], &[I8]),
(Opcode::StackLoad, &[], &[I16]), (Opcode::StackLoad, &[], &[I16]),
(Opcode::StackLoad, &[], &[I32]), (Opcode::StackLoad, &[], &[I32]),
(Opcode::StackLoad, &[], &[I64]), (Opcode::StackLoad, &[], &[I64]),
(Opcode::StackLoad, &[], &[I128]), (Opcode::StackLoad, &[], &[I128]),
(Opcode::StackLoad, &[], &[F32]),
(Opcode::StackLoad, &[], &[F64]),
(Opcode::StackLoad, &[], &[I8X16]),
(Opcode::StackLoad, &[], &[I16X8]),
(Opcode::StackLoad, &[], &[I32X4]),
(Opcode::StackLoad, &[], &[I64X2]),
(Opcode::StackLoad, &[], &[F32X4]),
(Opcode::StackLoad, &[], &[F64X2]),
// Loads // Loads
(Opcode::Load, &[], &[I8]), (Opcode::Load, &[], &[I8]),
(Opcode::Load, &[], &[I16]), (Opcode::Load, &[], &[I16]),
@@ -1266,6 +1508,12 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::Load, &[], &[I128]), (Opcode::Load, &[], &[I128]),
(Opcode::Load, &[], &[F32]), (Opcode::Load, &[], &[F32]),
(Opcode::Load, &[], &[F64]), (Opcode::Load, &[], &[F64]),
(Opcode::Load, &[], &[I8X16]),
(Opcode::Load, &[], &[I16X8]),
(Opcode::Load, &[], &[I32X4]),
(Opcode::Load, &[], &[I64X2]),
(Opcode::Load, &[], &[F32X4]),
(Opcode::Load, &[], &[F64X2]),
// Special Loads // Special Loads
(Opcode::Uload8, &[], &[I16]), (Opcode::Uload8, &[], &[I16]),
(Opcode::Uload8, &[], &[I32]), (Opcode::Uload8, &[], &[I32]),
@@ -1299,6 +1547,12 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::Store, &[I128], &[]), (Opcode::Store, &[I128], &[]),
(Opcode::Store, &[F32], &[]), (Opcode::Store, &[F32], &[]),
(Opcode::Store, &[F64], &[]), (Opcode::Store, &[F64], &[]),
(Opcode::Store, &[I8X16], &[]),
(Opcode::Store, &[I16X8], &[]),
(Opcode::Store, &[I32X4], &[]),
(Opcode::Store, &[I64X2], &[]),
(Opcode::Store, &[F32X4], &[]),
(Opcode::Store, &[F64X2], &[]),
// Special Stores // Special Stores
(Opcode::Istore8, &[I16], &[]), (Opcode::Istore8, &[I16], &[]),
(Opcode::Istore8, &[I32], &[]), (Opcode::Istore8, &[I32], &[]),
@@ -1326,6 +1580,76 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
(Opcode::Bitcast, &[I32], &[F32]), (Opcode::Bitcast, &[I32], &[F32]),
(Opcode::Bitcast, &[F64], &[I64]), (Opcode::Bitcast, &[F64], &[I64]),
(Opcode::Bitcast, &[I64], &[F64]), (Opcode::Bitcast, &[I64], &[F64]),
// Shuffle
(Opcode::Shuffle, &[I8X16, I8X16, I8X16], &[I8X16]),
// Swizzle
(Opcode::Swizzle, &[I8X16, I8X16], &[I8X16]),
// Splat
(Opcode::Splat, &[I8], &[I8X16]),
(Opcode::Splat, &[I16], &[I16X8]),
(Opcode::Splat, &[I32], &[I32X4]),
(Opcode::Splat, &[I64], &[I64X2]),
(Opcode::Splat, &[F32], &[F32X4]),
(Opcode::Splat, &[F64], &[F64X2]),
// Insert Lane
(Opcode::Insertlane, &[I8X16, I8], &[I8X16]),
(Opcode::Insertlane, &[I16X8, I16], &[I16X8]),
(Opcode::Insertlane, &[I32X4, I32], &[I32X4]),
(Opcode::Insertlane, &[I64X2, I64], &[I64X2]),
(Opcode::Insertlane, &[F32X4, F32], &[F32X4]),
(Opcode::Insertlane, &[F64X2, F64], &[F64X2]),
// Extract Lane
(Opcode::Extractlane, &[I8X16], &[I8]),
(Opcode::Extractlane, &[I16X8], &[I16]),
(Opcode::Extractlane, &[I32X4], &[I32]),
(Opcode::Extractlane, &[I64X2], &[I64]),
(Opcode::Extractlane, &[F32X4], &[F32]),
(Opcode::Extractlane, &[F64X2], &[F64]),
// Snarrow
(Opcode::Snarrow, &[I64X2, I64X2], &[I32X4]),
(Opcode::Snarrow, &[I32X4, I32X4], &[I16X8]),
(Opcode::Snarrow, &[I16X8, I16X8], &[I8X16]),
// Unarrow
(Opcode::Unarrow, &[I64X2, I64X2], &[I32X4]),
(Opcode::Unarrow, &[I32X4, I32X4], &[I16X8]),
(Opcode::Unarrow, &[I16X8, I16X8], &[I8X16]),
// Uunarrow
(Opcode::Uunarrow, &[I64X2, I64X2], &[I32X4]),
(Opcode::Uunarrow, &[I32X4, I32X4], &[I16X8]),
(Opcode::Uunarrow, &[I16X8, I16X8], &[I8X16]),
// VhighBits
(Opcode::VhighBits, &[I8X16], &[I8]),
(Opcode::VhighBits, &[I16X8], &[I8]),
(Opcode::VhighBits, &[I32X4], &[I8]),
(Opcode::VhighBits, &[I64X2], &[I8]),
// VanyTrue
(Opcode::VanyTrue, &[I8X16, I8X16, I8X16], &[I8]),
(Opcode::VanyTrue, &[I16X8, I16X8, I16X8], &[I8]),
(Opcode::VanyTrue, &[I32X4, I32X4, I32X4], &[I8]),
(Opcode::VanyTrue, &[I64X2, I64X2, I64X2], &[I8]),
// SwidenLow
(Opcode::SwidenLow, &[I8X16], &[I16X8]),
(Opcode::SwidenLow, &[I16X8], &[I32X4]),
(Opcode::SwidenLow, &[I32X4], &[I64X2]),
// SwidenHigh
(Opcode::SwidenHigh, &[I8X16], &[I16X8]),
(Opcode::SwidenHigh, &[I16X8], &[I32X4]),
(Opcode::SwidenHigh, &[I32X4], &[I64X2]),
// UwidenLow
(Opcode::UwidenLow, &[I8X16], &[I16X8]),
(Opcode::UwidenLow, &[I16X8], &[I32X4]),
(Opcode::UwidenLow, &[I32X4], &[I64X2]),
// UwidenHigh
(Opcode::UwidenHigh, &[I8X16], &[I16X8]),
(Opcode::UwidenHigh, &[I16X8], &[I32X4]),
(Opcode::UwidenHigh, &[I32X4], &[I64X2]),
// SqmulRoundSat
(Opcode::SqmulRoundSat, &[I16X8, I16X8], &[I16X8]),
(Opcode::SqmulRoundSat, &[I32X4, I32X4], &[I32X4]),
// IaddPairwise
(Opcode::IaddPairwise, &[I8X16, I8X16], &[I8X16]),
(Opcode::IaddPairwise, &[I16X8, I16X8], &[I16X8]),
(Opcode::IaddPairwise, &[I32X4, I32X4], &[I32X4]),
// Integer Consts // Integer Consts
(Opcode::Iconst, &[], &[I8]), (Opcode::Iconst, &[], &[I8]),
(Opcode::Iconst, &[], &[I16]), (Opcode::Iconst, &[], &[I16]),
@@ -1334,6 +1658,13 @@ const OPCODE_SIGNATURES: &[OpcodeSignature] = &[
// Float Consts // Float Consts
(Opcode::F32const, &[], &[F32]), (Opcode::F32const, &[], &[F32]),
(Opcode::F64const, &[], &[F64]), (Opcode::F64const, &[], &[F64]),
// Vector Consts
(Opcode::Vconst, &[], &[I8X16]),
(Opcode::Vconst, &[], &[I16X8]),
(Opcode::Vconst, &[], &[I32X4]),
(Opcode::Vconst, &[], &[I64X2]),
(Opcode::Vconst, &[], &[F32X4]),
(Opcode::Vconst, &[], &[F64X2]),
// Call // Call
(Opcode::Call, &[], &[]), (Opcode::Call, &[], &[]),
]; ];
@@ -1344,7 +1675,7 @@ fn inserter_for_format(fmt: InstructionFormat) -> OpcodeInserter {
InstructionFormat::AtomicRmw => insert_atomic_rmw, InstructionFormat::AtomicRmw => insert_atomic_rmw,
InstructionFormat::Binary => insert_opcode, InstructionFormat::Binary => insert_opcode,
InstructionFormat::BinaryImm64 => todo!(), InstructionFormat::BinaryImm64 => todo!(),
InstructionFormat::BinaryImm8 => todo!(), InstructionFormat::BinaryImm8 => insert_ins_ext_lane,
InstructionFormat::Call => insert_call, InstructionFormat::Call => insert_call,
InstructionFormat::CallIndirect => insert_call, InstructionFormat::CallIndirect => insert_call,
InstructionFormat::CondTrap => todo!(), InstructionFormat::CondTrap => todo!(),
@@ -1358,14 +1689,14 @@ fn inserter_for_format(fmt: InstructionFormat) -> OpcodeInserter {
InstructionFormat::Load => insert_load_store, InstructionFormat::Load => insert_load_store,
InstructionFormat::LoadNoOffset => insert_load_store, InstructionFormat::LoadNoOffset => insert_load_store,
InstructionFormat::NullAry => insert_opcode, InstructionFormat::NullAry => insert_opcode,
InstructionFormat::Shuffle => todo!(), InstructionFormat::Shuffle => insert_shuffle,
InstructionFormat::StackLoad => insert_stack_load, InstructionFormat::StackLoad => insert_stack_load,
InstructionFormat::StackStore => insert_stack_store, InstructionFormat::StackStore => insert_stack_store,
InstructionFormat::Store => insert_load_store, InstructionFormat::Store => insert_load_store,
InstructionFormat::StoreNoOffset => insert_load_store, InstructionFormat::StoreNoOffset => insert_load_store,
InstructionFormat::TableAddr => todo!(), InstructionFormat::TableAddr => todo!(),
InstructionFormat::Ternary => insert_opcode, InstructionFormat::Ternary => insert_opcode,
InstructionFormat::TernaryImm8 => todo!(), InstructionFormat::TernaryImm8 => insert_ins_ext_lane,
InstructionFormat::Trap => todo!(), InstructionFormat::Trap => todo!(),
InstructionFormat::Unary => insert_opcode, InstructionFormat::Unary => insert_opcode,
InstructionFormat::UnaryConst => insert_const, InstructionFormat::UnaryConst => insert_const,
@@ -1561,6 +1892,12 @@ where
); );
let aligned = if is_atomic && requires_aligned_atomics { let aligned = if is_atomic && requires_aligned_atomics {
true true
} else if min_size > 8 {
// TODO: We currently can't guarantee that a stack_slot will be aligned on a 16 byte
// boundary. We don't have a way to specify alignment when creating stack slots, and
// cranelift only guarantees 8 byte alignment between stack slots.
// See: https://github.com/bytecodealliance/wasmtime/issues/5922#issuecomment-1457926624
false
} else { } else {
bool::arbitrary(self.u)? bool::arbitrary(self.u)?
}; };