///|
fn lower_signedness(
signedness : @milkir.VectorSignedness,
) -> @semantic.Signedness {
match signedness {
Signed => Signed
Unsigned => Unsigned
}
}
///|
fn lower_vector_half(half : @milkir.VectorHalf) -> @semantic.VectorHalf {
match half {
Low => Low
High => High
}
}
///|
fn lower_integer_lane(lane : @milkir.VectorIntLane) -> @semantic.VectorLane {
match lane {
I8 => I8x16
I16 => I16x8
I32 => I32x4
I64 => I64x2
}
}
///|
fn lower_float_lane(lane : @milkir.VectorFloatLane) -> @semantic.VectorLane {
match lane {
F32 => F32x4
F64 => F64x2
}
}
///|
fn lower_lane(lane : @milkir.VectorLane) -> @semantic.VectorLane {
match lane {
I8 => I8x16
I16 => I16x8
I32 => I32x4
I64 => I64x2
F32 => F32x4
F64 => F64x2
}
}
///|
fn lower_extension(
extension : @milkir.VectorExtension,
) -> @semantic.Signedness? {
match extension {
None => None
Signed => Some(Signed)
Unsigned => Some(Unsigned)
}
}
///|
fn bytes_word(bytes : Bytes, offset : Int) -> UInt64 {
let mut word = 0UL
for index in 0..<8 {
word = word | (bytes[offset + index].to_int().to_uint64() << (index * 8))
}
word
}
///|
fn lower_int_unary_vector(
operation : @milkir.VectorIntUnaryOp,
lane : @milkir.VectorIntLane,
) -> @semantic.VectorOp {
let lane = lower_integer_lane(lane)
match operation {
Abs => IntUnary(lane, Absolute)
Neg => IntUnary(lane, Negate)
Popcnt => IntUnary(lane, PopulationCount)
Extend(half, signedness) =>
Convert(
match half {
Low => ExtendLow(lane, lower_signedness(signedness))
High => ExtendHigh(lane, lower_signedness(signedness))
},
)
ExtAddPairwise(signedness) =>
IntUnary(lane, ExtendAddPairwise(lower_signedness(signedness)))
}
}
///|
fn lower_int_binary_vector(
operation : @milkir.VectorIntBinaryOp,
lane : @milkir.VectorIntLane,
) -> @semantic.VectorOp {
let lane = lower_integer_lane(lane)
let operation : @semantic.VectorIntBinaryOp = match operation {
Add => Add
Sub => Sub
Mul => Mul
AddSaturating(signedness) => SaturatingAdd(lower_signedness(signedness))
SubSaturating(signedness) => SaturatingSub(lower_signedness(signedness))
Min(signedness) => Min(lower_signedness(signedness))
Max(signedness) => Max(lower_signedness(signedness))
AverageUnsigned => AverageUnsigned
ExtMul(half, signedness) =>
ExtendMultiply(lower_vector_half(half), lower_signedness(signedness))
Dot16To32Signed => Dot16To32Signed
Q15MulrSaturating => Q15MultiplyRoundedSaturating
}
IntBinary(lane, operation)
}
///|
fn lower_int_shift_vector(
operation : @milkir.VectorIntShiftOp,
lane : @milkir.VectorIntLane,
) -> @semantic.VectorOp {
let operation : @semantic.VectorIntShiftOp = match operation {
Left => Left
Right(signedness) => Right(lower_signedness(signedness))
}
IntShift(lower_integer_lane(lane), operation)
}
///|
fn lower_int_compare_vector(
operation : @milkir.VectorIntCompareOp,
lane : @milkir.VectorIntLane,
) -> @semantic.VectorOp {
let operation : @semantic.VectorIntComparison = match operation {
Eq => Equal
Ne => NotEqual
Lt(signedness) => LessThan(lower_signedness(signedness))
Le(signedness) => LessOrEqual(lower_signedness(signedness))
Gt(signedness) => GreaterThan(lower_signedness(signedness))
Ge(signedness) => GreaterOrEqual(lower_signedness(signedness))
}
IntCompare(lower_integer_lane(lane), operation)
}
///|
fn lower_float_unary_vector(
operation : @milkir.VectorFloatUnaryOp,
lane : @milkir.VectorFloatLane,
) -> @semantic.VectorOp {
let operation : @semantic.VectorFloatUnaryOp = match operation {
Abs => Absolute
Neg => Negate
Sqrt => SquareRoot
Ceil => Ceil
Floor => Floor
Trunc => Truncate
Nearest => Nearest
}
FloatUnary(lower_float_lane(lane), operation)
}
///|
fn lower_float_binary_vector(
operation : @milkir.VectorFloatBinaryOp,
lane : @milkir.VectorFloatLane,
) -> @semantic.VectorOp {
let operation : @semantic.VectorFloatBinaryOp = match operation {
Add => Add
Sub => Sub
Mul => Mul
Div => Div
Min => Min
Max => Max
PseudoMin => PseudoMin
PseudoMax => PseudoMax
}
FloatBinary(lower_float_lane(lane), operation)
}
///|
fn lower_float_compare_vector(
operation : @milkir.VectorFloatCompareOp,
lane : @milkir.VectorFloatLane,
) -> @semantic.VectorOp {
let operation : @semantic.VectorFloatComparison = match operation {
Eq => Equal
Ne => NotEqual
Lt => LessThan
Le => LessOrEqual
Gt => GreaterThan
Ge => GreaterOrEqual
}
FloatCompare(lower_float_lane(lane), operation)
}
///|
fn lower_vector_conversion(
operation : @milkir.VectorConversionOp,
) -> @semantic.VectorOp {
Convert(
match operation {
TruncSatF32ToI32(signedness) =>
FloatToInt(F32x4, I32x4, lower_signedness(signedness), Saturating)
TruncSatF64ToI32Zero(signedness) =>
FloatToInt(F64x2, I32x4, lower_signedness(signedness), Saturating)
ConvertI32ToF32(signedness) =>
IntToFloat(I32x4, F32x4, lower_signedness(signedness))
ConvertLowI32ToF64(signedness) =>
IntToFloat(I32x4, F64x2, lower_signedness(signedness))
DemoteF64ToF32Zero => DemoteZeroF64x2
PromoteLowF32ToF64 => PromoteLowF32x4
},
)
}
///|
fn lower_relaxed_vector(
operation : @milkir.VectorRelaxedOp,
) -> @semantic.VectorOp {
Relaxed(
match operation {
Swizzle => Swizzle
TruncF32ToI32(signedness) =>
FloatToInt(F32x4, I32x4, lower_signedness(signedness))
TruncF64ToI32Zero(signedness) =>
FloatToInt(F64x2, I32x4, lower_signedness(signedness))
Fma(lane, operation) =>
FusedMultiplyAdd(
lower_float_lane(lane),
match operation {
Add => FusedMultiplyAdd
NegatedAdd => FusedNegatedMultiplyAdd
},
)
LaneSelect(lane) => LaneSelect(lower_integer_lane(lane))
Min(lane) => Min(lower_float_lane(lane))
Max(lane) => Max(lower_float_lane(lane))
Q15MulrSigned => Q15MultiplyRoundedSigned
Dot8To16Signed => Dot8To16Signed
Dot8To32AddSigned => Dot8To32AddSigned
},
)
}
///|
fn lower_vector_operation(operation : @milkir.VectorOp) -> @semantic.Operation {
match operation {
Const(bytes) => V128Const(bytes_word(bytes, 0), bytes_word(bytes, 8))
Splat(lane) => Vector(Splat(lower_lane(lane)))
ExtractLane(lane, extension, index) =>
Vector(ExtractLane(lower_lane(lane), index, lower_extension(extension)))
ReplaceLane(lane, index) => Vector(ReplaceLane(lower_lane(lane), index))
Shuffle(mask) => Vector(Shuffle(mask))
Swizzle => Vector(Swizzle)
Bitwise(operation) =>
Vector(
Bitwise(
match operation {
Not => Not
And => And
AndNot => AndNot
Or => Or
Xor => Xor
Bitselect => BitSelect
},
),
)
Predicate(operation) =>
Vector(
Predicate(
match operation {
AnyTrue => AnyTrue
AllTrue(lane) => AllTrue(lower_integer_lane(lane))
Bitmask(lane) => BitMask(lower_integer_lane(lane))
},
),
)
IntUnary(operation, lane) => Vector(lower_int_unary_vector(operation, lane))
IntBinary(operation, lane) =>
Vector(lower_int_binary_vector(operation, lane))
IntShift(operation, lane) => Vector(lower_int_shift_vector(operation, lane))
IntCompare(operation, lane) =>
Vector(lower_int_compare_vector(operation, lane))
Narrow(lane, signedness) =>
Vector(
Convert(Narrow(lower_integer_lane(lane), lower_signedness(signedness))),
)
FloatUnary(operation, lane) =>
Vector(lower_float_unary_vector(operation, lane))
FloatBinary(operation, lane) =>
Vector(lower_float_binary_vector(operation, lane))
FloatCompare(operation, lane) =>
Vector(lower_float_compare_vector(operation, lane))
Convert(operation) => Vector(lower_vector_conversion(operation))
Relaxed(operation) => Vector(lower_relaxed_vector(operation))
}
}
///|
fn lower_vector_instruction(
builder : @semantic.FunctionBuilder,
values : Array[@semantic.Value?],
instruction : @milkir.Inst,
operation : @milkir.VectorOp,
) -> Unit raise SemanticLowerError {
let lowered_results = builder.emit_with_metadata(
lower_vector_operation(operation),
mapped_values(values, instruction.args),
instruction.results.map(value => lower_type(value.ty)),
instruction_metadata(instruction, []),
)
assign_instruction_results(values, instruction, lowered_results)
}
///|
fn widened_lane(lane : @milkir.VectorIntLane) -> @semantic.VectorLane {
match lane {
I8 => I16x8
I16 => I32x4
I32 => I64x2
I64 => I64x2
}
}
///|
fn lower_vector_memory_instruction(
builder : @semantic.FunctionBuilder,
values : Array[@semantic.Value?],
value_types : Array[@semantic.ValueType?],
instruction : @milkir.Inst,
operation : @milkir.VectorMemoryOp,
) -> Unit raise SemanticLowerError {
let address = lower_pointer_value(
builder,
values,
value_types,
instruction.args[0],
instruction_source(instruction),
instruction.id,
)
let (operation, operands, result_types) : (
@semantic.Operation,
Array[@semantic.Value],
Array[@semantic.ValueType],
) = match operation {
LoadExtend(lane, signedness) =>
(
VectorLoad(
@semantic.VectorLoadSpec::new(
Extend(widened_lane(lane), lower_signedness(signedness)),
0UL,
Little,
None,
),
),
[address],
[V128],
)
LoadSplat(lane) =>
(
VectorLoad(
@semantic.VectorLoadSpec::new(
Splat(lower_integer_lane(lane)),
0UL,
Little,
None,
),
),
[address],
[V128],
)
LoadZero(lane) =>
(
VectorLoad(
@semantic.VectorLoadSpec::new(
Zero(if lane is I32 { W32 } else { W64 }),
0UL,
Little,
None,
),
),
[address],
[V128],
)
LoadLane(lane, index) =>
(
VectorLoad(
@semantic.VectorLoadSpec::new(
Lane(lower_integer_lane(lane), index),
0UL,
Little,
None,
),
),
[address, mapped_value(values, instruction.args[1])],
[V128],
)
StoreLane(lane, index) =>
(
VectorStoreLane(
@semantic.VectorStoreLaneSpec::new(
lower_integer_lane(lane),
index,
0UL,
Little,
None,
),
),
[address, mapped_value(values, instruction.args[1])],
[],
)
}
let lowered_results = builder.emit_with_metadata(
operation,
operands,
result_types,
instruction_metadata(instruction, []),
)
assign_instruction_results(values, instruction, lowered_results)
}