///|
#derive(Eq, Debug)
pub(all) enum VectorConversion {
ExtendLow(@lowering.VectorLane, @native.Signedness)
ExtendHigh(@lowering.VectorLane, @native.Signedness)
Narrow(@lowering.VectorLane, @native.Signedness)
FloatToInt(@lowering.VectorLane, @native.Signedness)
IntToFloat(@lowering.VectorLane, @native.Signedness)
PromoteLowF32x4
DemoteZeroF64x2
}
///|
pub extend VectorConversion with Debug::{to_repr}
///|
pub extend VectorConversion with Eq::{not_equal, equal}
///|
pub fn select_vector_conversion(
operation : @lowering.VectorConversionOp,
) -> VectorConversion? {
match operation {
ExtendLow(lane, signedness) => Some(ExtendLow(lane, signedness))
ExtendHigh(lane, signedness) => Some(ExtendHigh(lane, signedness))
Narrow(lane, signedness) => Some(Narrow(lane, signedness))
FloatToInt(source, I32x4, signedness, Saturating) =>
Some(FloatToInt(source, signedness))
IntToFloat(I32x4, result, signedness) =>
Some(IntToFloat(result, signedness))
PromoteLowF32x4 => Some(PromoteLowF32x4)
DemoteZeroF64x2 => Some(DemoteZeroF64x2)
_ => None
}
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_extract_lane(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
index : Int32,
has_extension : Bool,
) -> Unit raise TargetVCodeVerifyError {
let requires_extension = lane == I8x16 || lane == I16x8
if index < 0 ||
index >= lane.lane_count() ||
requires_extension != has_extension {
raise InvalidInstruction(
instruction=self.instruction,
message="invalid vector lane extraction contract",
)
}
self.shape([V128], [lane.scalar_type()])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_replace_lane(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
index : Int32,
) -> Unit raise TargetVCodeVerifyError {
if index < 0 || index >= lane.lane_count() {
raise InvalidInstruction(
instruction=self.instruction,
message="invalid vector lane replacement index",
)
}
self.shape([V128, lane.scalar_type()], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_shuffle(
self : TargetInstructionVerifier[Inst],
mask : FixedArray[Int32],
) -> Unit raise TargetVCodeVerifyError {
if mask.length() != 16 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector shuffle requires exactly 16 lane indices",
)
}
for lane in mask {
if lane < 0 || lane >= 32 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector shuffle lane index is out of range",
)
}
}
self.shape([V128, V128], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_int_unary(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
operation : @lowering.VectorIntUnaryOp,
) -> Unit raise TargetVCodeVerifyError {
if !lane.is_integer() {
raise InvalidInstruction(
instruction=self.instruction,
message="vector integer unary operation requires integer lanes",
)
}
if operation is PopulationCount && lane != I8x16 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector population count requires i8x16 lanes",
)
}
if operation is ExtendAddPairwise(_) &&
lane != I16x8 &&
lane != I32x4 &&
lane != I64x2 {
raise InvalidInstruction(
instruction=self.instruction,
message="pairwise extending add requires widened integer lanes",
)
}
self.shape([V128], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_int_binary(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
operation : @lowering.VectorIntBinaryOp,
) -> Unit raise TargetVCodeVerifyError {
if !lane.is_integer() {
raise InvalidInstruction(
instruction=self.instruction,
message="vector integer binary operation requires integer lanes",
)
}
if operation is AverageUnsigned && lane != I8x16 && lane != I16x8 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector unsigned average requires i8x16 or i16x8 lanes",
)
}
if operation is ExtendMultiply(_, _) &&
lane != I16x8 &&
lane != I32x4 &&
lane != I64x2 {
raise InvalidInstruction(
instruction=self.instruction,
message="extending multiply requires widened integer lanes",
)
}
if operation is Dot16To32Signed && lane != I32x4 {
raise InvalidInstruction(
instruction=self.instruction,
message="dot16-to32 requires i32x4 destination lanes",
)
}
if operation is Q15MultiplyRoundedSaturating && lane != I16x8 {
raise InvalidInstruction(
instruction=self.instruction,
message="q15 rounded saturating multiply requires i16x8 lanes",
)
}
self.shape([V128, V128], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_int_shift(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
) -> Unit raise TargetVCodeVerifyError {
if !lane.is_integer() {
raise InvalidInstruction(
instruction=self.instruction,
message="vector integer shift requires integer lanes",
)
}
self.shape([V128, I32], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_int_compare(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
) -> Unit raise TargetVCodeVerifyError {
if !lane.is_integer() {
raise InvalidInstruction(
instruction=self.instruction,
message="vector integer comparison requires integer lanes",
)
}
self.shape([V128, V128], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_float_unary(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
) -> Unit raise TargetVCodeVerifyError {
if lane != F32x4 && lane != F64x2 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector float unary operation requires floating lanes",
)
}
self.shape([V128], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_float_binary(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
) -> Unit raise TargetVCodeVerifyError {
if lane != F32x4 && lane != F64x2 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector float operation requires floating lanes",
)
}
self.shape([V128, V128], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_float_ternary(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
) -> Unit raise TargetVCodeVerifyError {
if lane != F32x4 && lane != F64x2 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector float ternary operation requires floating lanes",
)
}
self.shape([V128, V128, V128], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_bitwise(
self : TargetInstructionVerifier[Inst],
operation : @lowering.VectorBitwiseOp,
) -> Unit raise TargetVCodeVerifyError {
let arity = match operation {
Not => 1
And | Or | Xor | AndNot => 2
BitSelect => 3
}
self.shape(Array::make(arity, V128), [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_load_zero(
self : TargetInstructionVerifier[Inst],
width : @native.AccessWidth,
) -> Unit raise TargetVCodeVerifyError {
if width != W32 && width != W64 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector load-zero requires width 32 or 64",
)
}
self.shape([Ptr64], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_load_extend(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
) -> Unit raise TargetVCodeVerifyError {
if lane != I16x8 && lane != I32x4 && lane != I64x2 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector load-extend requires widened integer lanes",
)
}
self.shape([Ptr64], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_load_lane(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
index : Int32,
) -> Unit raise TargetVCodeVerifyError {
if index < 0 || index >= lane.lane_count() {
raise InvalidInstruction(
instruction=self.instruction,
message="vector load-lane index is out of range",
)
}
self.shape([Ptr64, V128], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_store_lane(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
index : Int32,
) -> Unit raise TargetVCodeVerifyError {
if index < 0 || index >= lane.lane_count() {
raise InvalidInstruction(
instruction=self.instruction,
message="vector store-lane index is out of range",
)
}
self.shape([Ptr64, V128], [])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_conversion(
self : TargetInstructionVerifier[Inst],
conversion : VectorConversion,
) -> Unit raise TargetVCodeVerifyError {
match conversion {
ExtendLow(lane, _) | ExtendHigh(lane, _) => self.vector_extend(lane)
Narrow(lane, _) => self.vector_narrow(lane)
FloatToInt(source, _) => self.vector_float_to_int(source)
IntToFloat(result, _) => self.vector_int_to_float(result)
PromoteLowF32x4 | DemoteZeroF64x2 => self.shape([V128], [V128])
}
}
///|
fn[Inst] TargetInstructionVerifier::vector_extend(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
) -> Unit raise TargetVCodeVerifyError {
if lane != I16x8 && lane != I32x4 && lane != I64x2 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector extension requires widened integer lanes",
)
}
self.shape([V128], [V128])
}
///|
fn[Inst] TargetInstructionVerifier::vector_narrow(
self : TargetInstructionVerifier[Inst],
lane : @lowering.VectorLane,
) -> Unit raise TargetVCodeVerifyError {
if lane != I8x16 && lane != I16x8 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector narrowing requires i8x16 or i16x8 lanes",
)
}
self.shape([V128, V128], [V128])
}
///|
fn[Inst] TargetInstructionVerifier::vector_float_to_int(
self : TargetInstructionVerifier[Inst],
source : @lowering.VectorLane,
) -> Unit raise TargetVCodeVerifyError {
if source != F32x4 && source != F64x2 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector float-to-int requires f32x4 or f64x2 source lanes",
)
}
self.shape([V128], [V128])
}
///|
fn[Inst] TargetInstructionVerifier::vector_int_to_float(
self : TargetInstructionVerifier[Inst],
result : @lowering.VectorLane,
) -> Unit raise TargetVCodeVerifyError {
if result != F32x4 && result != F64x2 {
raise InvalidInstruction(
instruction=self.instruction,
message="vector int-to-float requires f32x4 or f64x2 result lanes",
)
}
self.shape([V128], [V128])
}
///|
pub fn[Inst] TargetInstructionVerifier::vector_predicate(
self : TargetInstructionVerifier[Inst],
predicate : @lowering.VectorPredicateOp,
) -> Unit raise TargetVCodeVerifyError {
match predicate {
AllTrue(lane) if !lane.is_integer() =>
raise InvalidInstruction(
instruction=self.instruction,
message="vector all-true predicate requires integer lanes",
)
BitMask(lane) if !lane.is_integer() =>
raise InvalidInstruction(
instruction=self.instruction,
message="vector bitmask predicate requires integer lanes",
)
_ => self.shape([V128], [I32])
}
}