[llvm] [AMDGPU][GlobalISel] Add BF16 widening to V2BF16 for packed instructions (PR #214370)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 5 16:56:39 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-amdgpu

Author: LU-JOHN

<details>
<summary>Changes</summary>

 Implement custom lowering in GlobalISel to widen scalar BF16 operations
 (FADD, FMUL, FMA, FCANONICALIZE) to V2BF16, enabling use of packed BF16
 instructions (v_pk_add_bf16, v_pk_mul_bf16, v_pk_fma_bf16).

Assisted by Claude.

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


3 Files Affected:

- (modified) llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp (+43) 
- (modified) llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.h (+3) 
- (added) llvm/test/CodeGen/AMDGPU/packed-bf16.ll (+261) 


``````````diff
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
index f4c30b7907b32..10328a2f6fe98 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
@@ -1008,6 +1008,10 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
     FPOpActions.clampMaxNumElementsStrict(0, F64, 2);
   }
 
+  if (ST.hasBF16PackedInsts()) {
+    FPOpActions.customFor({BF16}).legalFor({V2BF16});
+  }
+
   auto &MinNumMaxNumIeee =
       getActionDefinitionsBuilder({G_FMINNUM_IEEE, G_FMAXNUM_IEEE});
 
@@ -2288,6 +2292,40 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
   verify(*ST.getInstrInfo());
 }
 
+bool AMDGPULegalizerInfo::legalizeScalarBF16ToPackedBF16Op(
+    MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const {
+  Register Dst = MI.getOperand(0).getReg();
+  LLT DstTy = MRI.getType(Dst);
+
+  // Only handle scalar bf16
+  if (DstTy != LLT::bfloat16())
+    return false;
+
+  unsigned Opc = MI.getOpcode();
+  LLT V2BF16 = LLT::fixed_vector(2, LLT::bfloat16());
+  Register UndefBF16 = B.buildUndef(LLT::bfloat16()).getReg(0);
+
+  // Widen all source operands to v2bf16
+  SmallVector<Register, 3> WideSrcs;
+  for (unsigned I = 1, E = MI.getNumOperands(); I < E; ++I) {
+    Register Src = MI.getOperand(I).getReg();
+    Register WideSrc = B.buildBuildVector(V2BF16, {Src, UndefBF16}).getReg(0);
+    WideSrcs.push_back(WideSrc);
+  }
+
+  // Build the wide operation
+  auto MIB = B.buildInstr(Opc).addDef(MRI.createGenericVirtualRegister(V2BF16));
+  for (Register WideSrc : WideSrcs)
+    MIB.addUse(WideSrc);
+  Register WideResult = MIB.getReg(0);
+
+  // Extract element 0
+  B.buildExtractVectorElementConstant(Dst, WideResult, 0);
+
+  MI.eraseFromParent();
+  return true;
+}
+
 bool AMDGPULegalizerInfo::legalizeCustom(
     LegalizerHelper &Helper, MachineInstr &MI,
     LostDebugLocObserver &LocObserver) const {
@@ -2391,6 +2429,11 @@ bool AMDGPULegalizerInfo::legalizeCustom(
     return legalizeTrap(MI, MRI, B);
   case TargetOpcode::G_DEBUGTRAP:
     return legalizeDebugTrap(MI, MRI, B);
+  case TargetOpcode::G_FADD:
+  case TargetOpcode::G_FMUL:
+  case TargetOpcode::G_FMA:
+  case TargetOpcode::G_FCANONICALIZE:
+    return legalizeScalarBF16ToPackedBF16Op(MI, MRI, B);
   default:
     return false;
   }
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.h b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.h
index 89819fe990f5a..75a10297c6efe 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.h
@@ -43,6 +43,9 @@ class AMDGPULegalizerInfo final : public LegalizerInfo {
 
   bool legalizeAddrSpaceCast(MachineInstr &MI, MachineRegisterInfo &MRI,
                              MachineIRBuilder &B) const;
+  bool legalizeScalarBF16ToPackedBF16Op(MachineInstr &MI,
+                                        MachineRegisterInfo &MRI,
+                                        MachineIRBuilder &B) const;
   bool legalizeFroundeven(MachineInstr &MI, MachineRegisterInfo &MRI,
                           MachineIRBuilder &B) const;
   bool legalizeFceil(MachineInstr &MI, MachineRegisterInfo &MRI,
diff --git a/llvm/test/CodeGen/AMDGPU/packed-bf16.ll b/llvm/test/CodeGen/AMDGPU/packed-bf16.ll
new file mode 100644
index 0000000000000..f4ee127c8aa64
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/packed-bf16.ll
@@ -0,0 +1,261 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
+; RUN: llc -global-isel=0 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1250 -mattr=+real-true16 < %s | FileCheck --check-prefixes=GCN,SDAG,SDAG-TRUE16 %s
+; RUN: llc -global-isel=0 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1250 -mattr=-real-true16 < %s | FileCheck --check-prefixes=GCN,SDAG,SDAG-FAKE16 %s
+; RUN: llc -global-isel=1 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1250 -mattr=+real-true16 < %s | FileCheck --check-prefixes=GCN,GISEL,GISEL-TRUE16 %s
+; RUN: llc -global-isel=1 -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1250 -mattr=-real-true16 < %s | FileCheck --check-prefixes=GCN,GISEL,GISEL-FAKE16 %s
+
+; Test BF16 operations that have packed BF16 instruction variants.
+; Tests both scalar BF16 (widened to V2BF16) and native V2BF16 types.
+; Operations tested: FADD, FMUL, FMA, FCANONICALIZE
+; TODO: Add tests for FMAXNUM, FMINNUM, FNEG, FABS once GlobalISel support is added
+
+define bfloat @test_fadd_bf16(bfloat %a, bfloat %b) {
+; SDAG-LABEL: test_fadd_bf16:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    s_wait_loadcnt_dscnt 0x0
+; SDAG-NEXT:    s_wait_kmcnt 0x0
+; SDAG-NEXT:    v_pk_add_bf16 v0, v0, v1
+; SDAG-NEXT:    s_set_pc_i64 s[30:31]
+;
+; GISEL-TRUE16-LABEL: test_fadd_bf16:
+; GISEL-TRUE16:       ; %bb.0:
+; GISEL-TRUE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GISEL-TRUE16-NEXT:    s_wait_kmcnt 0x0
+; GISEL-TRUE16-NEXT:    v_pk_add_bf16 v0, v0, v1
+; GISEL-TRUE16-NEXT:    s_set_pc_i64 s[30:31]
+;
+; GISEL-FAKE16-LABEL: test_fadd_bf16:
+; GISEL-FAKE16:       ; %bb.0:
+; GISEL-FAKE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GISEL-FAKE16-NEXT:    s_wait_kmcnt 0x0
+; GISEL-FAKE16-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GISEL-FAKE16-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GISEL-FAKE16-NEXT:    v_lshl_or_b32 v0, s0, 16, v0
+; GISEL-FAKE16-NEXT:    v_lshl_or_b32 v1, s0, 16, v1
+; GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GISEL-FAKE16-NEXT:    v_pk_add_bf16 v0, v0, v1
+; GISEL-FAKE16-NEXT:    s_set_pc_i64 s[30:31]
+  %result = fadd bfloat %a, %b
+  ret bfloat %result
+}
+
+define <2 x bfloat> @test_fadd_v2bf16(<2 x bfloat> %a, <2 x bfloat> %b) {
+; GCN-LABEL: test_fadd_v2bf16:
+; GCN:       ; %bb.0:
+; GCN-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GCN-NEXT:    s_wait_kmcnt 0x0
+; GCN-NEXT:    v_pk_add_bf16 v0, v0, v1
+; GCN-NEXT:    s_set_pc_i64 s[30:31]
+  %result = fadd <2 x bfloat> %a, %b
+  ret <2 x bfloat> %result
+}
+
+define bfloat @test_fmul_bf16(bfloat %a, bfloat %b) {
+; SDAG-LABEL: test_fmul_bf16:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    s_wait_loadcnt_dscnt 0x0
+; SDAG-NEXT:    s_wait_kmcnt 0x0
+; SDAG-NEXT:    v_pk_mul_bf16 v0, v0, v1
+; SDAG-NEXT:    s_set_pc_i64 s[30:31]
+;
+; GISEL-TRUE16-LABEL: test_fmul_bf16:
+; GISEL-TRUE16:       ; %bb.0:
+; GISEL-TRUE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GISEL-TRUE16-NEXT:    s_wait_kmcnt 0x0
+; GISEL-TRUE16-NEXT:    v_pk_mul_bf16 v0, v0, v1
+; GISEL-TRUE16-NEXT:    s_set_pc_i64 s[30:31]
+;
+; GISEL-FAKE16-LABEL: test_fmul_bf16:
+; GISEL-FAKE16:       ; %bb.0:
+; GISEL-FAKE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GISEL-FAKE16-NEXT:    s_wait_kmcnt 0x0
+; GISEL-FAKE16-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GISEL-FAKE16-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GISEL-FAKE16-NEXT:    v_lshl_or_b32 v0, s0, 16, v0
+; GISEL-FAKE16-NEXT:    v_lshl_or_b32 v1, s0, 16, v1
+; GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GISEL-FAKE16-NEXT:    v_pk_mul_bf16 v0, v0, v1
+; GISEL-FAKE16-NEXT:    s_set_pc_i64 s[30:31]
+  %result = fmul bfloat %a, %b
+  ret bfloat %result
+}
+
+define <2 x bfloat> @test_fmul_v2bf16(<2 x bfloat> %a, <2 x bfloat> %b) {
+; GCN-LABEL: test_fmul_v2bf16:
+; GCN:       ; %bb.0:
+; GCN-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GCN-NEXT:    s_wait_kmcnt 0x0
+; GCN-NEXT:    v_pk_mul_bf16 v0, v0, v1
+; GCN-NEXT:    s_set_pc_i64 s[30:31]
+  %result = fmul <2 x bfloat> %a, %b
+  ret <2 x bfloat> %result
+}
+
+define bfloat @test_fma_bf16(bfloat %a, bfloat %b, bfloat %c) {
+; SDAG-LABEL: test_fma_bf16:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    s_wait_loadcnt_dscnt 0x0
+; SDAG-NEXT:    s_wait_kmcnt 0x0
+; SDAG-NEXT:    v_fma_mixlo_bf16 v0, v0, v1, v2 op_sel_hi:[1,1,1]
+; SDAG-NEXT:    s_set_pc_i64 s[30:31]
+;
+; GISEL-TRUE16-LABEL: test_fma_bf16:
+; GISEL-TRUE16:       ; %bb.0:
+; GISEL-TRUE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GISEL-TRUE16-NEXT:    s_wait_kmcnt 0x0
+; GISEL-TRUE16-NEXT:    v_pk_fma_bf16 v0, v0, v1, v2
+; GISEL-TRUE16-NEXT:    s_set_pc_i64 s[30:31]
+;
+; GISEL-FAKE16-LABEL: test_fma_bf16:
+; GISEL-FAKE16:       ; %bb.0:
+; GISEL-FAKE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GISEL-FAKE16-NEXT:    s_wait_kmcnt 0x0
+; GISEL-FAKE16-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GISEL-FAKE16-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GISEL-FAKE16-NEXT:    v_and_b32_e32 v2, 0xffff, v2
+; GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_3)
+; GISEL-FAKE16-NEXT:    v_lshl_or_b32 v0, s0, 16, v0
+; GISEL-FAKE16-NEXT:    v_lshl_or_b32 v1, s0, 16, v1
+; GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GISEL-FAKE16-NEXT:    v_lshl_or_b32 v2, s0, 16, v2
+; GISEL-FAKE16-NEXT:    v_pk_fma_bf16 v0, v0, v1, v2
+; GISEL-FAKE16-NEXT:    s_set_pc_i64 s[30:31]
+  %result = call bfloat @llvm.fma.bf16(bfloat %a, bfloat %b, bfloat %c)
+  ret bfloat %result
+}
+
+define <2 x bfloat> @test_fma_v2bf16(<2 x bfloat> %a, <2 x bfloat> %b, <2 x bfloat> %c) {
+; GCN-LABEL: test_fma_v2bf16:
+; GCN:       ; %bb.0:
+; GCN-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GCN-NEXT:    s_wait_kmcnt 0x0
+; GCN-NEXT:    v_pk_fma_bf16 v0, v0, v1, v2
+; GCN-NEXT:    s_set_pc_i64 s[30:31]
+  %result = call <2 x bfloat> @llvm.fma.v2bf16(<2 x bfloat> %a, <2 x bfloat> %b, <2 x bfloat> %c)
+  ret <2 x bfloat> %result
+}
+
+define bfloat @test_canonicalize_bf16(bfloat %a) {
+; SDAG-LABEL: test_canonicalize_bf16:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    s_wait_loadcnt_dscnt 0x0
+; SDAG-NEXT:    s_wait_kmcnt 0x0
+; SDAG-NEXT:    v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; SDAG-NEXT:    s_set_pc_i64 s[30:31]
+;
+; GISEL-TRUE16-LABEL: test_canonicalize_bf16:
+; GISEL-TRUE16:       ; %bb.0:
+; GISEL-TRUE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GISEL-TRUE16-NEXT:    s_wait_kmcnt 0x0
+; GISEL-TRUE16-NEXT:    v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; GISEL-TRUE16-NEXT:    s_set_pc_i64 s[30:31]
+;
+; GISEL-FAKE16-LABEL: test_canonicalize_bf16:
+; GISEL-FAKE16:       ; %bb.0:
+; GISEL-FAKE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GISEL-FAKE16-NEXT:    s_wait_kmcnt 0x0
+; GISEL-FAKE16-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GISEL-FAKE16-NEXT:    v_lshl_or_b32 v0, s0, 16, v0
+; GISEL-FAKE16-NEXT:    v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; GISEL-FAKE16-NEXT:    s_set_pc_i64 s[30:31]
+  %result = call bfloat @llvm.canonicalize.bf16(bfloat %a)
+  ret bfloat %result
+}
+
+define <2 x bfloat> @test_canonicalize_v2bf16(<2 x bfloat> %a) {
+; GCN-LABEL: test_canonicalize_v2bf16:
+; GCN:       ; %bb.0:
+; GCN-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GCN-NEXT:    s_wait_kmcnt 0x0
+; GCN-NEXT:    v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; GCN-NEXT:    s_set_pc_i64 s[30:31]
+  %result = call <2 x bfloat> @llvm.canonicalize.v2bf16(<2 x bfloat> %a)
+  ret <2 x bfloat> %result
+}
+
+define bfloat @test_complex_bf16(bfloat %a, bfloat %b, bfloat %c) {
+; SDAG-TRUE16-LABEL: test_complex_bf16:
+; SDAG-TRUE16:       ; %bb.0:
+; SDAG-TRUE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; SDAG-TRUE16-NEXT:    s_wait_kmcnt 0x0
+; SDAG-TRUE16-NEXT:    v_pk_mul_bf16 v0, v0, v1
+; SDAG-TRUE16-NEXT:    v_mov_b16_e32 v1.l, v2.l
+; SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; SDAG-TRUE16-NEXT:    v_pk_add_bf16 v0, v0, v1
+; SDAG-TRUE16-NEXT:    v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; SDAG-TRUE16-NEXT:    s_set_pc_i64 s[30:31]
+;
+; SDAG-FAKE16-LABEL: test_complex_bf16:
+; SDAG-FAKE16:       ; %bb.0:
+; SDAG-FAKE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; SDAG-FAKE16-NEXT:    s_wait_kmcnt 0x0
+; SDAG-FAKE16-NEXT:    v_pk_mul_bf16 v0, v0, v1
+; SDAG-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; SDAG-FAKE16-NEXT:    v_pk_add_bf16 v0, v0, v2
+; SDAG-FAKE16-NEXT:    v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; SDAG-FAKE16-NEXT:    s_set_pc_i64 s[30:31]
+;
+; GISEL-TRUE16-LABEL: test_complex_bf16:
+; GISEL-TRUE16:       ; %bb.0:
+; GISEL-TRUE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GISEL-TRUE16-NEXT:    s_wait_kmcnt 0x0
+; GISEL-TRUE16-NEXT:    v_pk_mul_bf16 v0, v0, v1
+; GISEL-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GISEL-TRUE16-NEXT:    v_pk_add_bf16 v0, v0, v2
+; GISEL-TRUE16-NEXT:    s_set_pc_i64 s[30:31]
+;
+; GISEL-FAKE16-LABEL: test_complex_bf16:
+; GISEL-FAKE16:       ; %bb.0:
+; GISEL-FAKE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GISEL-FAKE16-NEXT:    s_wait_kmcnt 0x0
+; GISEL-FAKE16-NEXT:    v_and_b32_e32 v0, 0xffff, v0
+; GISEL-FAKE16-NEXT:    v_and_b32_e32 v1, 0xffff, v1
+; GISEL-FAKE16-NEXT:    v_and_b32_e32 v2, 0xffff, v2
+; GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_3)
+; GISEL-FAKE16-NEXT:    v_lshl_or_b32 v0, s0, 16, v0
+; GISEL-FAKE16-NEXT:    v_lshl_or_b32 v1, s0, 16, v1
+; GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_4)
+; GISEL-FAKE16-NEXT:    v_pk_mul_bf16 v0, v0, v1
+; GISEL-FAKE16-NEXT:    v_lshl_or_b32 v1, s0, 16, v2
+; GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GISEL-FAKE16-NEXT:    v_pk_add_bf16 v0, v0, v1
+; GISEL-FAKE16-NEXT:    s_set_pc_i64 s[30:31]
+  %mul = fmul bfloat %a, %b
+  %add = fadd bfloat %mul, %c
+  %canon = call bfloat @llvm.canonicalize.bf16(bfloat %add)
+  ret bfloat %canon
+}
+
+; Test multiple packed operations in sequence
+define <2 x bfloat> @test_complex_v2bf16(<2 x bfloat> %a, <2 x bfloat> %b, <2 x bfloat> %c) {
+; SDAG-LABEL: test_complex_v2bf16:
+; SDAG:       ; %bb.0:
+; SDAG-NEXT:    s_wait_loadcnt_dscnt 0x0
+; SDAG-NEXT:    s_wait_kmcnt 0x0
+; SDAG-NEXT:    v_pk_mul_bf16 v0, v0, v1
+; SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; SDAG-NEXT:    v_pk_add_bf16 v0, v0, v2
+; SDAG-NEXT:    v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; SDAG-NEXT:    s_set_pc_i64 s[30:31]
+;
+; GISEL-LABEL: test_complex_v2bf16:
+; GISEL:       ; %bb.0:
+; GISEL-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GISEL-NEXT:    s_wait_kmcnt 0x0
+; GISEL-NEXT:    v_pk_mul_bf16 v0, v0, v1
+; GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GISEL-NEXT:    v_pk_add_bf16 v0, v0, v2
+; GISEL-NEXT:    s_set_pc_i64 s[30:31]
+  %mul = fmul <2 x bfloat> %a, %b
+  %add = fadd <2 x bfloat> %mul, %c
+  %canon = call <2 x bfloat> @llvm.canonicalize.v2bf16(<2 x bfloat> %add)
+  ret <2 x bfloat> %canon
+}
+
+declare bfloat @llvm.fma.bf16(bfloat, bfloat, bfloat)
+declare <2 x bfloat> @llvm.fma.v2bf16(<2 x bfloat>, <2 x bfloat>, <2 x bfloat>)
+declare bfloat @llvm.canonicalize.bf16(bfloat)
+declare <2 x bfloat> @llvm.canonicalize.v2bf16(<2 x bfloat>)

``````````

</details>


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


More information about the llvm-commits mailing list