aarch64: Migrate imul to ISLE
This commit migrates the `imul` clif instruction lowering for AArch64 to ISLE. This is a relatively complicated instruction with lots of special cases due to the simd proposal for wasm. Like x64, however, the special casing lends itself to ISLE quite well and the lowerings here in theory are pretty straightforward. The main gotcha of this commit is that this encounters a unique situation which hasn't been encountered yet with other lowerings, namely the `Umlal32` instruction used in the implementation of `i64x2.mul` is unique in the `VecRRRLongOp` class of instructions in that it both reads and writes the destination register (`use_mod` instead of simply `use_def`). This meant that I needed to add another helper in ISLe for creating a `vec_rrrr_long` instruction (despite this enum variant not actually existing) which implicitly moves the first operand into the destination before issuing the actual `VecRRRLong` instruction.
This commit is contained in:
@@ -71,102 +71,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||
|
||||
Opcode::Ineg => implemented_in_isle(ctx),
|
||||
|
||||
Opcode::Imul => {
|
||||
let ty = ty.unwrap();
|
||||
if ty == I128 {
|
||||
let lhs = put_input_in_regs(ctx, inputs[0]);
|
||||
let rhs = put_input_in_regs(ctx, inputs[1]);
|
||||
let dst = get_output_reg(ctx, outputs[0]);
|
||||
assert_eq!(lhs.len(), 2);
|
||||
assert_eq!(rhs.len(), 2);
|
||||
assert_eq!(dst.len(), 2);
|
||||
|
||||
// 128bit mul formula:
|
||||
// dst_lo = lhs_lo * rhs_lo
|
||||
// dst_hi = umulhi(lhs_lo, rhs_lo) + (lhs_lo * rhs_hi) + (lhs_hi * rhs_lo)
|
||||
//
|
||||
// We can convert the above formula into the following
|
||||
// umulh dst_hi, lhs_lo, rhs_lo
|
||||
// madd dst_hi, lhs_lo, rhs_hi, dst_hi
|
||||
// madd dst_hi, lhs_hi, rhs_lo, dst_hi
|
||||
// mul dst_lo, lhs_lo, rhs_lo
|
||||
|
||||
ctx.emit(Inst::AluRRR {
|
||||
alu_op: ALUOp::UMulH,
|
||||
rd: dst.regs()[1],
|
||||
rn: lhs.regs()[0],
|
||||
rm: rhs.regs()[0],
|
||||
});
|
||||
ctx.emit(Inst::AluRRRR {
|
||||
alu_op: ALUOp3::MAdd64,
|
||||
rd: dst.regs()[1],
|
||||
rn: lhs.regs()[0],
|
||||
rm: rhs.regs()[1],
|
||||
ra: dst.regs()[1].to_reg(),
|
||||
});
|
||||
ctx.emit(Inst::AluRRRR {
|
||||
alu_op: ALUOp3::MAdd64,
|
||||
rd: dst.regs()[1],
|
||||
rn: lhs.regs()[1],
|
||||
rm: rhs.regs()[0],
|
||||
ra: dst.regs()[1].to_reg(),
|
||||
});
|
||||
ctx.emit(Inst::AluRRRR {
|
||||
alu_op: ALUOp3::MAdd64,
|
||||
rd: dst.regs()[0],
|
||||
rn: lhs.regs()[0],
|
||||
rm: rhs.regs()[0],
|
||||
ra: zero_reg(),
|
||||
});
|
||||
} else if ty.is_vector() {
|
||||
for ext_op in &[
|
||||
Opcode::SwidenLow,
|
||||
Opcode::SwidenHigh,
|
||||
Opcode::UwidenLow,
|
||||
Opcode::UwidenHigh,
|
||||
] {
|
||||
if let Some((alu_op, rn, rm, high_half)) =
|
||||
match_vec_long_mul(ctx, insn, *ext_op)
|
||||
{
|
||||
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
||||
ctx.emit(Inst::VecRRRLong {
|
||||
alu_op,
|
||||
rd,
|
||||
rn,
|
||||
rm,
|
||||
high_half,
|
||||
});
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
if ty == I64X2 {
|
||||
lower_i64x2_mul(ctx, insn);
|
||||
} else {
|
||||
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
|
||||
let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None);
|
||||
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
||||
ctx.emit(Inst::VecRRR {
|
||||
alu_op: VecALUOp::Mul,
|
||||
rd,
|
||||
rn,
|
||||
rm,
|
||||
size: VectorSize::from_ty(ty),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
let alu_op = choose_32_64(ty, ALUOp3::MAdd32, ALUOp3::MAdd64);
|
||||
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
|
||||
let rm = put_input_in_reg(ctx, inputs[1], NarrowValueMode::None);
|
||||
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
||||
ctx.emit(Inst::AluRRRR {
|
||||
alu_op,
|
||||
rd,
|
||||
rn,
|
||||
rm,
|
||||
ra: zero_reg(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Opcode::Imul => implemented_in_isle(ctx),
|
||||
|
||||
Opcode::Umulhi | Opcode::Smulhi => {
|
||||
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user