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
