llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-powerpc

Author: Ben Richard (benrichard-amd)

<details>
<summary>Changes</summary>

Hi,

This PR enables `__bf16` on PowerPC via software promotion to float32, as it 
does not have native `bf16` support.

Tests included.

This change was assisted by Claude.

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


5 Files Affected:

- (modified) clang/lib/Basic/Targets/PPC.cpp (+6) 
- (modified) clang/lib/Basic/Targets/PPC.h (+3) 
- (added) clang/test/CodeGen/PowerPC/bfloat16.c (+45) 
- (modified) llvm/lib/Target/PowerPC/PPCISelLowering.cpp (+16) 
- (added) llvm/test/CodeGen/PowerPC/bfloat16-soft-promote.ll (+180) 


``````````diff
diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp
index c9a41df806aff..c1076f699d7e8 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -87,6 +87,12 @@ bool 
PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
     // all.
   }
 
+  // __bf16 is enabled by default in the constructor. Disable it on AIX
+  // (ABI not yet defined), soft-float, and SPE targets.
+  if (getTriple().isOSAIX() || FloatABI == SoftFloat || HasSPE) {
+    HasBFloat16 = false;
+  }
+
   return true;
 }
 
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index e3bf5072d932d..7ffe312d8ab16 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -83,9 +83,12 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public 
TargetInfo {
     SuitableAlign = 128;
     LongDoubleWidth = LongDoubleAlign = 128;
     LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble();
+    BFloat16Width = BFloat16Align = 16;
+    BFloat16Format = &llvm::APFloat::BFloat();
     HasStrictFP = true;
     HasIbm128 = true;
     HasUnalignedAccess = true;
+    HasBFloat16 = true;
   }
 
   // Set the language option for altivec based on our value.
diff --git a/clang/test/CodeGen/PowerPC/bfloat16.c 
b/clang/test/CodeGen/PowerPC/bfloat16.c
new file mode 100644
index 0000000000000..47d3ed2e87dbc
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/bfloat16.c
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple powerpc64le-linux-gnu -emit-llvm -o - %s \
+// RUN:   | FileCheck %s --check-prefix=PPC64LE
+// RUN: %clang_cc1 -triple powerpc-linux-gnu -emit-llvm -o - %s \
+// RUN:   | FileCheck %s --check-prefix=PPC32
+// RUN: %clang_cc1 -triple powerpc64le-linux-gnu -target-cpu pwr10 -emit-llvm 
-o - %s \
+// RUN:   | FileCheck %s --check-prefix=PPC64LE
+//
+// Test that __bf16 is accepted on PowerPC targets and that the Clang
+// frontend emits the expected bfloat IR type.
+
+// __bf16 must be accepted (no "not supported on this target" error).
+__bf16 global_bf;
+
+// PPC64LE: @global_bf = global bfloat
+// PPC32:   @global_bf = global bfloat
+
+// Function signatures use bfloat type.
+__bf16 add(__bf16 a, __bf16 b) {
+  return a + b;
+// PPC64LE-LABEL: define {{.*}} bfloat @add(bfloat noundef %a, bfloat noundef 
%b)
+// PPC32-LABEL:   define {{.*}} bfloat @add(bfloat noundef %a, bfloat noundef 
%b)
+}
+
+__bf16 mul(__bf16 a, __bf16 b) {
+  return a * b;
+// PPC64LE-LABEL: define {{.*}} bfloat @mul(bfloat noundef %a, bfloat noundef 
%b)
+// PPC32-LABEL:   define {{.*}} bfloat @mul(bfloat noundef %a, bfloat noundef 
%b)
+}
+
+// Extend/truncate round-trips.
+float to_float(__bf16 a) {
+  return (float)a;
+// PPC64LE: fpext bfloat {{.*}} to float
+// PPC32:   fpext bfloat {{.*}} to float
+}
+
+__bf16 from_float(float a) {
+  return (__bf16)a;
+// PPC64LE: fptrunc float {{.*}} to bfloat
+// PPC32:   fptrunc float {{.*}} to bfloat
+}
+
+// sizeof and alignof must both be 2.
+_Static_assert(sizeof(__bf16) == 2, "sizeof(__bf16) != 2");
+_Static_assert(_Alignof(__bf16) == 2, "_Alignof(__bf16) != 2");
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp 
b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index f6c844b6428ce..9b49c0d150e37 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -241,6 +241,22 @@ PPCTargetLowering::PPCTargetLowering(const 
PPCTargetMachine &TM,
   setTruncStoreAction(MVT::f128, MVT::f16, Expand);
   setOperationAction(ISD::FP_TO_FP16, MVT::f128, Expand);
 
+  // bf16 is soft-promoted to f32 on all PowerPC targets.
+  // Loads/stores use the integer i16 path (lhz/sth) via TypeSoftPromoteHalf.
+  // BF16_TO_FP (extend) is done inline via left-shift-16.
+  // FP_TO_BF16 (truncate) is done via the __truncsfbf2 libcall.
+  //
+  // BF16_TO_FP and FP_TO_BF16 must be explicitly marked Expand so that
+  // LegalizeDAG expands them to the shift+bitcast / libcall sequences before
+  // ISel.  Without this they default to Legal and reach ISel with no matching
+  // .td pattern, causing a "Cannot select" fatal error.
+  for (MVT VT : {MVT::f32, MVT::f64, MVT::f128}) {
+    setLoadExtAction(ISD::EXTLOAD, VT, MVT::bf16, Expand);
+    setTruncStoreAction(VT, MVT::bf16, Expand);
+    setOperationAction(ISD::BF16_TO_FP, VT, Expand);
+    setOperationAction(ISD::FP_TO_BF16, VT, Expand);
+  }
+
   if (Subtarget.isISA3_0()) {
     setLoadExtAction(ISD::EXTLOAD, MVT::f128, MVT::f16, Legal);
     setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Legal);
diff --git a/llvm/test/CodeGen/PowerPC/bfloat16-soft-promote.ll 
b/llvm/test/CodeGen/PowerPC/bfloat16-soft-promote.ll
new file mode 100644
index 0000000000000..0574ecf0d05a3
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/bfloat16-soft-promote.ll
@@ -0,0 +1,180 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; Tests for __bf16 (bfloat) soft-promotion on PowerPC.
+;
+; All PowerPC targets soft-promote bf16 to f32:
+;   - Loads/stores use integer lhz/sth (i16 path).
+;   - BF16_TO_FP (extend) is done inline via a left-shift of 16 bits.
+;   - FP_TO_BF16 (truncate) calls __truncsfbf2.
+;   - Arithmetic is performed in f32 and the result truncated back to bf16.
+
+; RUN: llc -mcpu=pwr8 -mtriple=powerpc64le-unknown-unknown \
+; RUN:   -verify-machineinstrs -ppc-asm-full-reg-names < %s | FileCheck %s \
+; RUN:   --check-prefixes=CHECK,P8
+; RUN: llc -mcpu=pwr10 -mtriple=powerpc64le-unknown-unknown \
+; RUN:   -verify-machineinstrs -ppc-asm-full-reg-names < %s | FileCheck %s \
+; RUN:   --check-prefixes=CHECK,P10
+
+define void @store_bf16(bfloat %x, ptr %p) nounwind {
+; CHECK-LABEL: store_bf16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    xsmaxdp f0, f1, f1
+; CHECK-NEXT:    xscvdpspn vs0, f0
+; CHECK-NEXT:    mffprwz r3, f0
+; CHECK-NEXT:    srwi r3, r3, 16
+; CHECK-NEXT:    sth r3, 0(r4)
+; CHECK-NEXT:    blr
+  store bfloat %x, ptr %p
+  ret void
+}
+
+define bfloat @load_bf16(ptr %p) nounwind {
+; CHECK-LABEL: load_bf16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lhz r3, 0(r3)
+; CHECK-NEXT:    slwi r3, r3, 16
+; CHECK-NEXT:    mtfprd f0, r3
+; CHECK-NEXT:    xxsldwi vs0, vs0, vs0, 1
+; CHECK-NEXT:    xscvspdpn f1, vs0
+; CHECK-NEXT:    blr
+  %v = load bfloat, ptr %p
+  ret bfloat %v
+}
+
+define float @extend_bf16_to_f32(bfloat %a) nounwind {
+; CHECK-LABEL: extend_bf16_to_f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    blr
+  %r = fpext bfloat %a to float
+  ret float %r
+}
+
+define bfloat @trunc_f32_to_bf16(float %a) nounwind {
+; CHECK-LABEL: trunc_f32_to_bf16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    xsmaxdp f0, f1, f1
+; CHECK-NEXT:    xscvdpspn vs0, f0
+; CHECK-NEXT:    mffprwz r3, f0
+; CHECK-NEXT:    rlwinm r3, r3, 0, 0, 15
+; CHECK-NEXT:    mtfprd f0, r3
+; CHECK-NEXT:    xxsldwi vs0, vs0, vs0, 1
+; CHECK-NEXT:    xscvspdpn f1, vs0
+; CHECK-NEXT:    blr
+  %r = fptrunc float %a to bfloat
+  ret bfloat %r
+}
+
+define bfloat @add_bf16(bfloat %a, bfloat %b) nounwind {
+; P8-LABEL: add_bf16:
+; P8:       # %bb.0:
+; P8-NEXT:    xsmaxdp f0, f1, f1
+; P8-NEXT:    xscvdpspn vs0, f0
+; P8-NEXT:    mffprwz r3, f0
+; P8-NEXT:    xsmaxdp f0, f2, f2
+; P8-NEXT:    xscvdpspn vs0, f0
+; P8-NEXT:    rlwinm r3, r3, 0, 0, 15
+; P8-NEXT:    mtfprd f1, r3
+; P8-NEXT:    mffprwz r4, f0
+; P8-NEXT:    rlwinm r4, r4, 0, 0, 15
+; P8-NEXT:    mtfprd f0, r4
+; P8-NEXT:    xxsldwi vs1, vs1, vs1, 1
+; P8-NEXT:    xscvspdpn f1, vs1
+; P8-NEXT:    xxsldwi vs0, vs0, vs0, 1
+; P8-NEXT:    xscvspdpn f0, vs0
+; P8-NEXT:    xsaddsp f0, f1, f0
+; P8-NEXT:    xscvdpspn vs0, f0
+; P8-NEXT:    mffprwz r3, f0
+; P8-NEXT:    rlwinm r3, r3, 0, 0, 15
+; P8-NEXT:    mtfprd f0, r3
+; P8-NEXT:    xxsldwi vs0, vs0, vs0, 1
+; P8-NEXT:    xscvspdpn f1, vs0
+; P8-NEXT:    blr
+;
+; P10-LABEL: add_bf16:
+; P10:       # %bb.0:
+; P10-NEXT:    xsmaxdp f0, f1, f1
+; P10-NEXT:    xscvdpspn vs0, f0
+; P10-NEXT:    mffprwz r3, f0
+; P10-NEXT:    xsmaxdp f0, f2, f2
+; P10-NEXT:    rlwinm r3, r3, 0, 0, 15
+; P10-NEXT:    xscvdpspn vs0, f0
+; P10-NEXT:    mtfprd f1, r3
+; P10-NEXT:    xxsldwi vs1, vs1, vs1, 1
+; P10-NEXT:    xscvspdpn f1, vs1
+; P10-NEXT:    mffprwz r4, f0
+; P10-NEXT:    rlwinm r4, r4, 0, 0, 15
+; P10-NEXT:    mtfprd f0, r4
+; P10-NEXT:    xxsldwi vs0, vs0, vs0, 1
+; P10-NEXT:    xscvspdpn f0, vs0
+; P10-NEXT:    xsaddsp f0, f1, f0
+; P10-NEXT:    xscvdpspn vs0, f0
+; P10-NEXT:    mffprwz r3, f0
+; P10-NEXT:    rlwinm r3, r3, 0, 0, 15
+; P10-NEXT:    mtfprd f0, r3
+; P10-NEXT:    xxsldwi vs0, vs0, vs0, 1
+; P10-NEXT:    xscvspdpn f1, vs0
+; P10-NEXT:    blr
+  %r = fadd bfloat %a, %b
+  ret bfloat %r
+}
+
+define i1 @cmp_bf16(bfloat %a, bfloat %b) nounwind {
+; P8-LABEL: cmp_bf16:
+; P8:       # %bb.0:
+; P8-NEXT:    xsmaxdp f0, f1, f1
+; P8-NEXT:    xscvdpspn vs0, f0
+; P8-NEXT:    mffprwz r3, f0
+; P8-NEXT:    xsmaxdp f0, f2, f2
+; P8-NEXT:    xscvdpspn vs0, f0
+; P8-NEXT:    rlwinm r3, r3, 0, 0, 15
+; P8-NEXT:    mtfprd f1, r3
+; P8-NEXT:    li r3, 0
+; P8-NEXT:    mffprwz r4, f0
+; P8-NEXT:    rlwinm r4, r4, 0, 0, 15
+; P8-NEXT:    mtfprd f0, r4
+; P8-NEXT:    li r4, 1
+; P8-NEXT:    xxsldwi vs1, vs1, vs1, 1
+; P8-NEXT:    xscvspdpn f1, vs1
+; P8-NEXT:    xxsldwi vs0, vs0, vs0, 1
+; P8-NEXT:    xscvspdpn f0, vs0
+; P8-NEXT:    fcmpu cr0, f1, f0
+; P8-NEXT:    isellt r3, r4, r3
+; P8-NEXT:    blr
+;
+; P10-LABEL: cmp_bf16:
+; P10:       # %bb.0:
+; P10-NEXT:    xsmaxdp f0, f1, f1
+; P10-NEXT:    xscvdpspn vs0, f0
+; P10-NEXT:    mffprwz r3, f0
+; P10-NEXT:    xsmaxdp f0, f2, f2
+; P10-NEXT:    rlwinm r3, r3, 0, 0, 15
+; P10-NEXT:    xscvdpspn vs0, f0
+; P10-NEXT:    mtfprd f1, r3
+; P10-NEXT:    xxsldwi vs1, vs1, vs1, 1
+; P10-NEXT:    xscvspdpn f1, vs1
+; P10-NEXT:    mffprwz r4, f0
+; P10-NEXT:    rlwinm r4, r4, 0, 0, 15
+; P10-NEXT:    mtfprd f0, r4
+; P10-NEXT:    xxsldwi vs0, vs0, vs0, 1
+; P10-NEXT:    xscvspdpn f0, vs0
+; P10-NEXT:    fcmpu cr0, f1, f0
+; P10-NEXT:    setbc r3, lt
+; P10-NEXT:    blr
+  %r = fcmp olt bfloat %a, %b
+  ret i1 %r
+}
+
+define bfloat @sitofp_i32_to_bf16(i32 %a) nounwind {
+; CHECK-LABEL: sitofp_i32_to_bf16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    mtfprwa f0, r3
+; CHECK-NEXT:    xscvsxdsp f0, f0
+; CHECK-NEXT:    xscvdpspn vs0, f0
+; CHECK-NEXT:    mffprwz r3, f0
+; CHECK-NEXT:    rlwinm r3, r3, 0, 0, 15
+; CHECK-NEXT:    mtfprd f0, r3
+; CHECK-NEXT:    xxsldwi vs0, vs0, vs0, 1
+; CHECK-NEXT:    xscvspdpn f1, vs0
+; CHECK-NEXT:    blr
+  %r = sitofp i32 %a to bfloat
+  ret bfloat %r
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/208598
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to