[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