Skip to content

[AMDGPU] Perform scalar FMUL with bf16 more efficiently - #213969

Merged
LU-JOHN merged 1 commit into
llvm:mainfrom
LU-JOHN:bf16_fmul
Aug 5, 2026
Merged

[AMDGPU] Perform scalar FMUL with bf16 more efficiently#213969
LU-JOHN merged 1 commit into
llvm:mainfrom
LU-JOHN:bf16_fmul

Conversation

@LU-JOHN

@LU-JOHN LU-JOHN commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Perform scalar FMUL with bf16 more efficiently. Utilize v2bf16 patterns.

@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-backend-amdgpu

Author: LU-JOHN

Changes

Perform scalar FMUL with bf16 more efficiently. Utilize v2bf16 patterns.


Full diff: https://github.com/llvm/llvm-project/pull/213969.diff

5 Files Affected:

  • (modified) llvm/lib/Target/AMDGPU/SIISelLowering.cpp (+9-7)
  • (modified) llvm/lib/Target/AMDGPU/SIISelLowering.h (+1-1)
  • (modified) llvm/test/CodeGen/AMDGPU/bf16.ll (+1-1)
  • (modified) llvm/test/CodeGen/AMDGPU/llvm.cos.bf16.ll (+2-6)
  • (modified) llvm/test/CodeGen/AMDGPU/llvm.sin.bf16.ll (+2-6)
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index e55356ab3ea24..189ec3fe1e3c1 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -247,6 +247,8 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
       // Widen scalar fcanonicalize to a v2bf16 operation with an unused high
       // lane.
       setOperationAction(ISD::FCANONICALIZE, MVT::bf16, Custom);
+      // Widen scalar fmul to a v2bf16 operation with an unused high lane.
+      setOperationAction(ISD::FMUL, MVT::bf16, Custom);
     }
 
     setOperationAction(ISD::FP_ROUND, MVT::bf16, Expand);
@@ -7718,7 +7720,6 @@ SDValue SITargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
   case ISD::SMAX:
   case ISD::UMIN:
   case ISD::UMAX:
-  case ISD::FMUL:
   case ISD::FMINNUM_IEEE:
   case ISD::FMAXNUM_IEEE:
   case ISD::UADDSAT:
@@ -7727,8 +7728,9 @@ SDValue SITargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
   case ISD::SSUBSAT:
     return splitBinaryVectorOp(Op, DAG);
   case ISD::FADD:
+  case ISD::FMUL:
     if (Op.getValueType() == MVT::bf16)
-      return lowerScalarBF16FAdd(Op, DAG);
+      return lowerScalarBF16BinaryOp(Op, DAG);
     return splitBinaryVectorOp(Op, DAG);
   case ISD::FCANONICALIZE:
     if (Op.getValueType() == MVT::bf16)
@@ -8797,8 +8799,8 @@ SDValue SITargetLowering::lowerFP_ROUND(SDValue Op, SelectionDAG &DAG) const {
                      DAG.getTargetConstant(0, DL, MVT::i32));
 }
 
-SDValue SITargetLowering::lowerScalarBF16FAdd(SDValue Op,
-                                              SelectionDAG &DAG) const {
+SDValue SITargetLowering::lowerScalarBF16BinaryOp(SDValue Op,
+                                                  SelectionDAG &DAG) const {
   assert(Subtarget->hasBF16PackedInsts());
 
   SDLoc DL(Op);
@@ -8815,10 +8817,10 @@ SDValue SITargetLowering::lowerScalarBF16FAdd(SDValue Op,
 
   SDValue LHS = WidenOperand(Op.getOperand(0));
   SDValue RHS = WidenOperand(Op.getOperand(1));
-  SDValue Add =
-      DAG.getNode(ISD::FADD, DL, MVT::v2bf16, LHS, RHS, Op->getFlags());
+  SDValue Result =
+      DAG.getNode(Op.getOpcode(), DL, MVT::v2bf16, LHS, RHS, Op->getFlags());
 
-  return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::bf16, Add,
+  return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::bf16, Result,
                      DAG.getConstant(0, DL, MVT::i32));
 }
 
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h
index f358f59311c79..3e0e5da94471f 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h
@@ -166,7 +166,7 @@ class SITargetLowering final : public AMDGPUTargetLowering {
   /// Custom lowering for ISD::FP_ROUND for MVT::f16.
   SDValue lowerFP_ROUND(SDValue Op, SelectionDAG &DAG) const;
   SDValue splitFP_ROUNDVectorOp(SDValue Op, SelectionDAG &DAG) const;
-  SDValue lowerScalarBF16FAdd(SDValue Op, SelectionDAG &DAG) const;
+  SDValue lowerScalarBF16BinaryOp(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerScalarBF16FCanonicalize(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerFMINNUM_FMAXNUM(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerFMINIMUMNUM_FMAXIMUMNUM(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/test/CodeGen/AMDGPU/bf16.ll b/llvm/test/CodeGen/AMDGPU/bf16.ll
index deb8f6e415b70..89006f14961eb 100644
--- a/llvm/test/CodeGen/AMDGPU/bf16.ll
+++ b/llvm/test/CodeGen/AMDGPU/bf16.ll
@@ -14442,7 +14442,7 @@ define bfloat @v_fmul_bf16(bfloat %a, bfloat %b) #0 {
 ; GFX1250:       ; %bb.0:
 ; GFX1250-NEXT:    s_wait_loadcnt_dscnt 0x0
 ; GFX1250-NEXT:    s_wait_kmcnt 0x0
-; GFX1250-NEXT:    v_fma_mixlo_bf16 v0, v0, v1, 0 op_sel_hi:[1,1,0]
+; GFX1250-NEXT:    v_pk_mul_bf16 v0, v0, v1
 ; GFX1250-NEXT:    s_set_pc_i64 s[30:31]
   %op = fmul bfloat %a, %b
   ret bfloat %op
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.cos.bf16.ll b/llvm/test/CodeGen/AMDGPU/llvm.cos.bf16.ll
index 8de3847f1df8c..097adde1dece0 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.cos.bf16.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.cos.bf16.ll
@@ -15,11 +15,9 @@ define amdgpu_kernel void @cos_bf16(ptr addrspace(1) %out, bfloat %src) #1 {
 ; FAKE16-NEXT:    v_nop
 ; FAKE16-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1 ; msbs: dst=0 src0=0 src1=0 src2=0
 ; FAKE16-NEXT:    s_load_b96 s[0:2], s[4:5], 0x24 nv
-; FAKE16-NEXT:    s_mov_b32 s3, 0x3e230000
 ; FAKE16-NEXT:    v_mov_b32_e32 v1, 0
 ; FAKE16-NEXT:    s_wait_kmcnt 0x0
-; FAKE16-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 0 ; msbs: dst=0 src0=0 src1=0 src2=0
-; FAKE16-NEXT:    v_fma_mixlo_bf16 v0, s2, s3, 0 op_sel_hi:[1,0,0]
+; FAKE16-NEXT:    v_pk_mul_bf16 v0, 0x3e23, s2
 ; FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
 ; FAKE16-NEXT:    v_cos_bf16_e32 v0, v0
 ; FAKE16-NEXT:    global_store_b16 v1, v0, s[0:1]
@@ -31,11 +29,9 @@ define amdgpu_kernel void @cos_bf16(ptr addrspace(1) %out, bfloat %src) #1 {
 ; REAL16-NEXT:    v_nop
 ; REAL16-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1 ; msbs: dst=0 src0=0 src1=0 src2=0
 ; REAL16-NEXT:    s_load_b96 s[0:2], s[4:5], 0x24 nv
-; REAL16-NEXT:    s_mov_b32 s3, 0x3e230000
 ; REAL16-NEXT:    v_mov_b32_e32 v1, 0
 ; REAL16-NEXT:    s_wait_kmcnt 0x0
-; REAL16-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 0 ; msbs: dst=0 src0=0 src1=0 src2=0
-; REAL16-NEXT:    v_fma_mixlo_bf16 v0, s2, s3, 0 op_sel_hi:[1,0,0]
+; REAL16-NEXT:    v_pk_mul_bf16 v0, 0x3e23, s2
 ; REAL16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
 ; REAL16-NEXT:    v_cos_bf16_e32 v0.l, v0.l
 ; REAL16-NEXT:    global_store_b16 v1, v0, s[0:1]
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.sin.bf16.ll b/llvm/test/CodeGen/AMDGPU/llvm.sin.bf16.ll
index ef331c8b0162d..d3eda06c9ddd1 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.sin.bf16.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.sin.bf16.ll
@@ -15,11 +15,9 @@ define amdgpu_kernel void @sin_bf16(ptr addrspace(1) %out, bfloat %src) #1 {
 ; FAKE16-NEXT:    v_nop
 ; FAKE16-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1 ; msbs: dst=0 src0=0 src1=0 src2=0
 ; FAKE16-NEXT:    s_load_b96 s[0:2], s[4:5], 0x24 nv
-; FAKE16-NEXT:    s_mov_b32 s3, 0x3e230000
 ; FAKE16-NEXT:    v_mov_b32_e32 v1, 0
 ; FAKE16-NEXT:    s_wait_kmcnt 0x0
-; FAKE16-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 0 ; msbs: dst=0 src0=0 src1=0 src2=0
-; FAKE16-NEXT:    v_fma_mixlo_bf16 v0, s2, s3, 0 op_sel_hi:[1,0,0]
+; FAKE16-NEXT:    v_pk_mul_bf16 v0, 0x3e23, s2
 ; FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
 ; FAKE16-NEXT:    v_sin_bf16_e32 v0, v0
 ; FAKE16-NEXT:    global_store_b16 v1, v0, s[0:1]
@@ -31,11 +29,9 @@ define amdgpu_kernel void @sin_bf16(ptr addrspace(1) %out, bfloat %src) #1 {
 ; REAL16-NEXT:    v_nop
 ; REAL16-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 25, 1), 1 ; msbs: dst=0 src0=0 src1=0 src2=0
 ; REAL16-NEXT:    s_load_b96 s[0:2], s[4:5], 0x24 nv
-; REAL16-NEXT:    s_mov_b32 s3, 0x3e230000
 ; REAL16-NEXT:    v_mov_b32_e32 v1, 0
 ; REAL16-NEXT:    s_wait_kmcnt 0x0
-; REAL16-NEXT:    s_setreg_imm32_b32 hwreg(HW_REG_WAVE_MODE, 2, 2), 0 ; msbs: dst=0 src0=0 src1=0 src2=0
-; REAL16-NEXT:    v_fma_mixlo_bf16 v0, s2, s3, 0 op_sel_hi:[1,0,0]
+; REAL16-NEXT:    v_pk_mul_bf16 v0, 0x3e23, s2
 ; REAL16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
 ; REAL16-NEXT:    v_sin_bf16_e32 v0.l, v0.l
 ; REAL16-NEXT:    global_store_b16 v1, v0, s[0:1]

@LU-JOHN
LU-JOHN force-pushed the bf16_fmul branch 2 times, most recently from 7bfbc3f to 5781d6e Compare August 4, 2026 23:08
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 201368 tests passed
  • 5529 tests skipped

✅ The build succeeded and all tests passed.

Signed-off-by: John Lu <John.Lu@amd.com>

@sommerlukas sommerlukas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, are we doing the same for GlobalISel or are you planning to add that?

@LU-JOHN

LU-JOHN commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Looks good, are we doing the same for GlobalISel or are you planning to add that?

I'm working on doing the same for FMUL and Canonicalize for GlobalISel.

@LU-JOHN
LU-JOHN merged commit 7972734 into llvm:main Aug 5, 2026
12 checks passed
jinge90 pushed a commit to jinge90/llvm-project that referenced this pull request Aug 6, 2026
Perform scalar FMUL with bf16 more efficiently. Utilize v2bf16 patterns.

Signed-off-by: John Lu <John.Lu@amd.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants