[llvm] [AMDGPU] Add OMOD folding for TRANS bfloat16 instructions (PR #208595)

Jay Foad via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 13 07:23:50 PDT 2026


================
@@ -2363,6 +2358,117 @@ SIFoldOperandsImpl::isOMod(const MachineInstr &MI) const {
 
     return std::pair(nullptr, SIOutMods::NONE);
   }
+  case AMDGPU::V_FMA_MIXLO_BF16:
+  case AMDGPU::V_FMA_MIX_BF16_t16: {
+    if (MFI->getMode().FP32Denormals.Output != DenormalMode::PreserveSign ||
+        MI.mayRaiseFPException())
+      return std::pair(nullptr, SIOutMods::NONE);
+
+    const MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
+    const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
+    const MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
+
+    if (!Src2 || !Src2->isImm() || Src2->getImm() != 0)
+      return std::pair(nullptr, SIOutMods::NONE);
+
+    // op_sel bits are in src*_modifiers but don't affect folding
+    const MachineOperand *Src0Mods =
+        TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers);
+    const MachineOperand *Src1Mods =
+        TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers);
+    if ((Src0Mods &&
+         (Src0Mods->getImm() & (SISrcMods::NEG | SISrcMods::ABS))) ||
+        (Src1Mods &&
+         (Src1Mods->getImm() & (SISrcMods::NEG | SISrcMods::ABS))) ||
+        TII->hasModifiersSet(MI, AMDGPU::OpName::omod) ||
+        TII->hasModifiersSet(MI, AMDGPU::OpName::clamp))
+      return std::pair(nullptr, SIOutMods::NONE);
+
+    if (!Src0->isReg() || !Src1->isReg())
+      return std::pair(nullptr, SIOutMods::NONE);
+
+    const MachineOperand *RegOp = nullptr;
+    int64_t ImmValue = 0;
+
+    const MachineInstr *Src1Def = MRI->getVRegDef(Src1->getReg());
+    if (Src1Def && Src1Def->isMoveImmediate() &&
+        Src1Def->getOperand(1).isImm()) {
+      ImmValue = Src1Def->getOperand(1).getImm();
+      RegOp = Src0;
+    } else {
+      const MachineInstr *Src0Def = MRI->getVRegDef(Src0->getReg());
+      if (Src0Def && Src0Def->isMoveImmediate() &&
+          Src0Def->getOperand(1).isImm()) {
+        ImmValue = Src0Def->getOperand(1).getImm();
+        RegOp = Src1;
+      } else {
+        return std::pair(nullptr, SIOutMods::NONE);
+      }
+    }
+
+    int OMod = getOModValue(AMDGPU::V_MUL_F32_e64, ImmValue);
+    if (OMod == SIOutMods::NONE)
+      return std::pair(nullptr, SIOutMods::NONE);
+
+    return std::pair(RegOp, OMod);
+  }
+  case AMDGPU::V_CVT_PK_BF16_F32_e64: {
+    // Fold cvt_pk_bf16_f32(fma_mix_f32_bf16(x, 1.0, x)) -> x with MUL2 omod
+    if (MFI->getMode().FP32Denormals.Output != DenormalMode::PreserveSign ||
----------------
jayfoad wrote:

> > I don't see V_CVT_PK_BF16_F32 in any of the tests you added.
> 
> %mul2 = fmul nsz bfloat %cos, 2.0 ==> something like %fma = v_fma_mix_f32_bf16 %cos, 1.0. %cos %mul2 = V_CVT_PK_BF16_F32 %fma

I see, it only shows up in the test _without_ your SIFoldOperands patch. Can you precommit the test to show the current codegen?

> > I'd also prefer this part in a separate PR because I think it's the first time isOMod is handling something with vector type, and we need to be careful about what that means: does it apply to all of the vector elements or just the first one? You seem to be assuming "just the first one".
> 
> We are handling three cases of omod:
> 
> 1. %mul2 = fmul nsz bfloat %cos, 2.0
> 2. %mul4 = fmul nsz bfloat %cos, 4.0
> 3. %div2 = fmul nsz bfloat %cos, 0.5
> 
> Do you mean we need to separate the PR for case 1? Thanks.

Yes.

https://github.com/llvm/llvm-project/pull/208595


More information about the llvm-commits mailing list