RISC-V and LoongArch64 JITs: Don't fuse the multiply-adds in Vec4Dot

A fused multiply-add rounds once where the IR interpreter rounds twice, so
vdot, vhdp, vtfm and vmmul gave different low bits. Multiply and add
separately, in the IR interpreter's order. (LoongArch's LSX path already
did, in the pairwise order of the x86 and ARM64 JITs.)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-15 14:41:51 +02:00
1 parent 21010a497f
commit ff42928673
2 files changed
+17 -31

No files matched your search

+6 -15
View File
@@ -370,21 +370,12 @@ void LoongArch64JitBackend::CompIR_VecHoriz(IRInst inst) {
// Do we need care about upper 96 bits?
VFADD_S(regs_.V(inst.dest), regs_.V(inst.dest), EncodeRegToV(SCRATCHF1));
} else {
if (Overlap(inst.dest, 1, inst.src1, 4) || Overlap(inst.dest, 1, inst.src2, 4)) {
// This means inst.dest overlaps one of src1 or src2. We have to do that one first.
// Technically this may impact -0.0 and such, but dots accurately need to be aligned anyway.
for (int i = 0; i < 4; ++i) {
if (inst.dest == inst.src1 + i || inst.dest == inst.src2 + i)
FMUL_S(regs_.F(inst.dest), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i));
}
for (int i = 0; i < 4; ++i) {
if (inst.dest != inst.src1 + i && inst.dest != inst.src2 + i)
FMADD_S(regs_.F(inst.dest), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i), regs_.F(inst.dest));
}
} else {
FMUL_S(regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));
for (int i = 1; i < 4; ++i)
FMADD_S(regs_.F(inst.dest), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i), regs_.F(inst.dest));
// Multiply and add separately in the IR interpreter's order: FMADD rounds differently.
// The sum builds up in a scratch reg, so dest may be one of the inputs.
FMUL_S(SCRATCHF1, regs_.F(inst.src1), regs_.F(inst.src2));
for (int i = 1; i < 4; ++i) {
FMUL_S(SCRATCHF2, regs_.F(inst.src1 + i), regs_.F(inst.src2 + i));
FADD_S(i == 3 ? regs_.F(inst.dest) : SCRATCHF1, SCRATCHF1, SCRATCHF2);
}
}
break;
+11 -16
View File
@@ -293,24 +293,19 @@ void RiscVJitBackend::CompIR_VecHoriz(IRInst inst) {
switch (inst.op) {
case IROp::Vec4Dot:
regs_.Map(inst);
if (Overlap(inst.dest, 1, inst.src1, 4) || Overlap(inst.dest, 1, inst.src2, 4)) {
// This means inst.dest overlaps one of src1 or src2. We have to do that one first.
// Technically this may impact -0.0 and such, but dots accurately need to be aligned anyway.
for (int i = 0; i < 4; ++i) {
if (inst.dest == inst.src1 + i || inst.dest == inst.src2 + i)
FMUL(32, regs_.F(inst.dest), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i));
}
for (int i = 0; i < 4; ++i) {
if (inst.dest != inst.src1 + i && inst.dest != inst.src2 + i)
FMADD(32, regs_.F(inst.dest), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i), regs_.F(inst.dest));
}
} else {
FMUL(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));
for (int i = 1; i < 4; ++i)
FMADD(32, regs_.F(inst.dest), regs_.F(inst.src1 + i), regs_.F(inst.src2 + i), regs_.F(inst.dest));
{
// Multiply and add separately in the IR interpreter's order: FMADD rounds differently.
// The sum builds up in dest, so it can't be one of the inputs.
if (Overlap(inst.dest, 1, inst.src1, 4) || Overlap(inst.dest, 1, inst.src2, 4))
DISABLE;
RiscVReg tempReg = regs_.MapWithFPRTemp(inst);
FMUL(32, regs_.F(inst.dest), regs_.F(inst.src1), regs_.F(inst.src2));
for (int i = 1; i < 4; ++i) {
FMUL(32, tempReg, regs_.F(inst.src1 + i), regs_.F(inst.src2 + i));
FADD(32, regs_.F(inst.dest), regs_.F(inst.dest), tempReg);
}
break;
}
case IROp::Vec4VfpuDot:
// Through the IR interpreter for now.