[llvm] [AMDGPU][True16] Fix MadMix selection (PR #205431)
Petar Avramovic via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 3 03:42:49 PDT 2026
================
@@ -7299,21 +7311,134 @@ AMDGPUInstructionSelector::selectVOP3PMadMixMods(MachineOperand &Root) const {
Register Src;
unsigned Mods;
bool Matched;
- bool NeedsWiden;
- std::tie(Src, Mods) = selectVOP3PMadMixModsImpl(Root, Matched, NeedsWiden);
+ std::tie(Src, Mods) = selectVOP3PMadMixModsImpl(Root, Matched);
+
+ if (madMixSrcNeedsWiden(Src))
+ std::tie(Src, Mods) = selectVOP3ModsImpl(Root.getReg());
- MachineRegisterInfo *RegInfo = MRI;
return {{
- [=](MachineInstrBuilder &MIB) {
- Register Reg = Src;
- if (NeedsWiden)
- Reg = createVOP3PSrc32FromLo16(Src, MIB.getInstr(), *RegInfo);
- MIB.addReg(Reg);
- },
+ [=](MachineInstrBuilder &MIB) { MIB.addReg(Src); },
[=](MachineInstrBuilder &MIB) { MIB.addImm(Mods); } // src_mods
}};
}
+// With real true16 instructions a 16-bit value lives in a VGPR_16, which cannot
+// be used as a source of the 32-bit mix instructions. Widening it needs a
+// REG_SEQUENCE
+bool AMDGPUInstructionSelector::selectVOP3PMadMixF32(MachineInstr &I) const {
+ if (!Subtarget->useRealTrue16Insts() || !Subtarget->hasFmaMixInsts())
+ return false;
+
+ Register Dst = I.getOperand(0).getReg();
+ if (MRI->getType(Dst) != LLT::scalar(32) ||
+ RBI.getRegBank(Dst, *MRI, TRI)->getID() != AMDGPU::VGPRRegBankID)
+ return false;
+
+ struct MixSrc {
+ Register Reg;
+ int64_t Imm = 0;
+ unsigned Mods = SISrcMods::NONE;
+ bool IsImm = false;
+ bool NeedsWiden = false;
+ } Srcs[3];
+
+ const auto MatchReg = [&](MixSrc &S, MachineOperand &Op) {
+ bool Matched;
+ std::tie(S.Reg, S.Mods) = selectVOP3PMadMixModsImpl(Op, Matched);
+ S.NeedsWiden = madMixSrcNeedsWiden(S.Reg);
+ };
+ const auto SetImm = [](MixSrc &S, int64_t Imm, unsigned Mods) {
+ S.IsImm = true;
+ S.Imm = Imm;
+ S.Mods = Mods;
+ };
+
+ switch (I.getOpcode()) {
+ case TargetOpcode::G_FMA:
+ MatchReg(Srcs[0], I.getOperand(1));
+ MatchReg(Srcs[1], I.getOperand(2));
+ MatchReg(Srcs[2], I.getOperand(3));
+ break;
+ case TargetOpcode::G_FADD:
+ // (fadd x, y) -> (fma x, 1.0, y)
+ MatchReg(Srcs[0], I.getOperand(1));
+ SetImm(Srcs[1], 0x3C00 /*half 1.0*/, SISrcMods::OP_SEL_1);
+ MatchReg(Srcs[2], I.getOperand(2));
+ break;
+ case TargetOpcode::G_FMUL:
+ // (fmul x, y) -> (fma x, y, -0.0)
+ MatchReg(Srcs[0], I.getOperand(1));
+ MatchReg(Srcs[1], I.getOperand(2));
+ SetImm(Srcs[2], 0, SISrcMods::NEG);
+ break;
+ case TargetOpcode::G_FSUB:
+ // (fsub x, y) -> (fma y, -1.0, x)
+ MatchReg(Srcs[0], I.getOperand(2));
+ SetImm(Srcs[1], 0xBC00 /*half -1.0*/, SISrcMods::OP_SEL_1);
+ MatchReg(Srcs[2], I.getOperand(1));
+ break;
+ default:
+ return false;
+ }
+
+ if (none_of(Srcs, [](const MixSrc &S) { return S.NeedsWiden; }))
+ return false;
+
+ // Constrain the sources that are about to be widened before creating
+ // anything, so that a failure here leaves the function untouched.
+ for (const MixSrc &S : Srcs) {
----------------
petar-avramovic wrote:
Think it should be possible to merge all three
`for (const MixSrc &S : Srcs) {`
loops
https://github.com/llvm/llvm-project/pull/205431
More information about the llvm-commits
mailing list