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 `_Float16` on PowerPC, bringing PowerPC in line with AArch64 and RISC-V which already support this type. On Power9 and later (e.g. `-mcpu=power9`) it will generate `XSCVHPDP`/`XSCVDPHP` instructions for f16<->f32 conversions. Unit tests included. Assisted-by: Claude <noreply@<!-- -->anthropic.com> --- Full diff: https://github.com/llvm/llvm-project/pull/208542.diff 7 Files Affected: - (modified) clang/lib/Basic/Targets/PPC.cpp (+6) - (modified) clang/lib/Basic/Targets/PPC.h (+6) - (added) clang/test/CodeGen/PowerPC/Float16.c (+45) - (modified) clang/test/Sema/Float16.c (+2) - (modified) clang/test/SemaCXX/Float16.cpp (+2) - (modified) llvm/lib/Target/PowerPC/PPCISelLowering.cpp (+7) - (added) llvm/test/CodeGen/PowerPC/float16-soft-promote.ll (+274) ``````````diff diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index c9a41df806aff..5d92c7d222e72 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. } + // _Float16 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) { + HasFloat16 = false; + } + return true; } diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index e3bf5072d932d..2c3f6a116b8f9 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -86,6 +86,12 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { HasStrictFP = true; HasIbm128 = true; HasUnalignedAccess = true; + // _Float16 is supported on all PowerPC Linux targets via software + // promotion to float32, matching the approach used by AArch64 and RISC-V. + // AIX, soft-float, and SPE targets clear this flag in + // handleTargetFeatures() since their ABI has not yet been defined. + HasFloat16 = true; + HasFastHalfType = false; } // Set the language option for altivec based on our value. diff --git a/clang/test/CodeGen/PowerPC/Float16.c b/clang/test/CodeGen/PowerPC/Float16.c new file mode 100644 index 0000000000000..0db3d1378d149 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/Float16.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 pwr9 -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=PPC64LE +// +// Test that _Float16 is accepted on PowerPC targets and that the Clang +// frontend emits the expected 'half' IR type for _Float16 arithmetic. + +// _Float16 must be accepted (no "not supported on this target" error). +_Float16 global_h = 1.0f16; + +// PPC64LE: @global_h = global half +// PPC32: @global_h = global half + +// Function signatures use 'half' type. +_Float16 add(_Float16 a, _Float16 b) { + return a + b; +// PPC64LE-LABEL: define {{.*}} half @add(half noundef %a, half noundef %b) +// PPC32-LABEL: define {{.*}} half @add(half noundef %a, half noundef %b) +} + +_Float16 mul(_Float16 a, _Float16 b) { + return a * b; +// PPC64LE-LABEL: define {{.*}} half @mul(half noundef %a, half noundef %b) +// PPC32-LABEL: define {{.*}} half @mul(half noundef %a, half noundef %b) +} + +// Extend/truncate round-trips. +float to_float(_Float16 a) { + return (float)a; +// PPC64LE: fpext half {{.*}} to float +// PPC32: fpext half {{.*}} to float +} + +_Float16 from_float(float a) { + return (_Float16)a; +// PPC64LE: fptrunc float {{.*}} to half +// PPC32: fptrunc float {{.*}} to half +} + +// sizeof must be 2 and _Alignof must be 2. +_Static_assert(sizeof(_Float16) == 2, "sizeof(_Float16) != 2"); +_Static_assert(_Alignof(_Float16) == 2, "_Alignof(_Float16) != 2"); diff --git a/clang/test/Sema/Float16.c b/clang/test/Sema/Float16.c index b104cf907b3e9..978ac69371ad1 100644 --- a/clang/test/Sema/Float16.c +++ b/clang/test/Sema/Float16.c @@ -6,6 +6,8 @@ // RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-linux-gnu %s -DHAVE // RUN: %clang_cc1 -fsyntax-only -verify -triple riscv32 %s -DHAVE // RUN: %clang_cc1 -fsyntax-only -verify -triple riscv64 %s -DHAVE +// RUN: %clang_cc1 -fsyntax-only -verify -triple powerpc-linux-gnu %s -DHAVE +// RUN: %clang_cc1 -fsyntax-only -verify -triple powerpc64le-linux-gnu %s -DHAVE // RUN: %clang_cc1 -fsyntax-only -verify -triple s390x-ibm-zos %s #ifndef HAVE diff --git a/clang/test/SemaCXX/Float16.cpp b/clang/test/SemaCXX/Float16.cpp index 9646a8d0c317f..c6e365c252094 100644 --- a/clang/test/SemaCXX/Float16.cpp +++ b/clang/test/SemaCXX/Float16.cpp @@ -4,6 +4,8 @@ // RUN: %clang_cc1 -fsyntax-only -verify -triple spir-unknown-unknown %s -DHAVE // RUN: %clang_cc1 -fsyntax-only -verify -triple armv7a-linux-gnu %s -DHAVE // RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-linux-gnu %s -DHAVE +// RUN: %clang_cc1 -fsyntax-only -verify -triple powerpc-linux-gnu %s -DHAVE +// RUN: %clang_cc1 -fsyntax-only -verify -triple powerpc64le-linux-gnu %s -DHAVE // RUN: %clang_cc1 -fsyntax-only -verify -triple s390x-ibm-zos %s #ifdef HAVE // expected-no-diagnostics diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index f6c844b6428ce..2c3d51c34bdf9 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -247,6 +247,13 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM, setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Legal); setTruncStoreAction(MVT::f64, MVT::f16, Legal); setTruncStoreAction(MVT::f32, MVT::f16, Legal); + // ISA 3.0 (Power9) has XSCVHPDP/XSCVDPHP for scalar HP<->DP conversion. + // Mark FP16_TO_FP / FP_TO_FP16 as Legal so the soft-promote machinery + // uses hardware instead of __extendhfsf2/__truncsfhf2 libcalls. + setOperationAction(ISD::FP16_TO_FP, MVT::f64, Legal); + setOperationAction(ISD::FP16_TO_FP, MVT::f32, Legal); + setOperationAction(ISD::FP_TO_FP16, MVT::f64, Legal); + setOperationAction(ISD::FP_TO_FP16, MVT::f32, Legal); } else { // No extending loads from f16 or HW conversions back and forth. setLoadExtAction(ISD::EXTLOAD, MVT::f128, MVT::f16, Expand); diff --git a/llvm/test/CodeGen/PowerPC/float16-soft-promote.ll b/llvm/test/CodeGen/PowerPC/float16-soft-promote.ll new file mode 100644 index 0000000000000..3cff5968c7723 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/float16-soft-promote.ll @@ -0,0 +1,274 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; Tests for _Float16 (half) soft-promotion on PowerPC. +; +; Sub-P9 (P8): all f16 arithmetic is promoted to f32 via __extendhfsf2 / +; __truncsfhf2 libcalls. Loads and stores use integer lhz/sth. +; +; P9 (ISA 3.0): load/store use LXSIHZX+XSCVHPDP / XSCVDPHP+STXSIHX. +; Register-to-register FP16_TO_FP / FP_TO_FP16 also use hardware. + +; 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=pwr9 -mtriple=powerpc64le-unknown-unknown \ +; RUN: -verify-machineinstrs -ppc-asm-full-reg-names < %s | FileCheck %s \ +; RUN: --check-prefixes=CHECK,P9 + +; --------------------------------------------------------------------------- +; Load / store (half is carried as i16 in memory on both P8 and P9) +; --------------------------------------------------------------------------- + +define void @store_f16(half %x, ptr %p) nounwind { +; CHECK-LABEL: store_f16: +; CHECK: # %bb.0: +; CHECK-NEXT: sth r3, 0(r4) +; CHECK-NEXT: blr + store half %x, ptr %p + ret void +} + +define half @load_f16(ptr %p) nounwind { +; CHECK-LABEL: load_f16: +; CHECK: # %bb.0: +; CHECK-NEXT: lhz r3, 0(r3) +; CHECK-NEXT: blr + %v = load half, ptr %p + ret half %v +} + +; --------------------------------------------------------------------------- +; Arithmetic: addition (soft-promote to f32 on P8, same on P9) +; --------------------------------------------------------------------------- + +define half @add_f16(half %a, half %b) nounwind { +; P8-LABEL: add_f16: +; P8: # %bb.0: +; P8-NEXT: mflr r0 +; P8-NEXT: std r30, -24(r1) # 8-byte Folded Spill +; P8-NEXT: stfd f31, -8(r1) # 8-byte Folded Spill +; P8-NEXT: stdu r1, -64(r1) +; P8-NEXT: mr r30, r3 +; P8-NEXT: clrldi r3, r4, 48 +; P8-NEXT: std r0, 80(r1) +; P8-NEXT: bl __extendhfsf2 +; P8-NEXT: nop +; P8-NEXT: clrldi r3, r30, 48 +; P8-NEXT: fmr f31, f1 +; P8-NEXT: bl __extendhfsf2 +; P8-NEXT: nop +; P8-NEXT: xsaddsp f1, f1, f31 +; P8-NEXT: bl __truncsfhf2 +; P8-NEXT: nop +; P8-NEXT: addi r1, r1, 64 +; P8-NEXT: ld r0, 16(r1) +; P8-NEXT: lfd f31, -8(r1) # 8-byte Folded Reload +; P8-NEXT: ld r30, -24(r1) # 8-byte Folded Reload +; P8-NEXT: mtlr r0 +; P8-NEXT: blr +; +; P9-LABEL: add_f16: +; P9: # %bb.0: +; P9-NEXT: clrlwi r3, r3, 16 +; P9-NEXT: clrlwi r4, r4, 16 +; P9-NEXT: mtfprwz f0, r4 +; P9-NEXT: mtfprwz f1, r3 +; P9-NEXT: xscvhpdp f0, f0 +; P9-NEXT: xscvhpdp f1, f1 +; P9-NEXT: xsaddsp f0, f1, f0 +; P9-NEXT: xscvdphp f0, f0 +; P9-NEXT: mffprwz r3, f0 +; P9-NEXT: blr + %r = fadd half %a, %b + ret half %r +} + +; --------------------------------------------------------------------------- +; Extend f16 -> f32 (soft: libcall on P8, hardware XSCVHPDP on P9) +; --------------------------------------------------------------------------- + +define float @extend_f16_to_f32(half %a) nounwind { +; P8-LABEL: extend_f16_to_f32: +; P8: # %bb.0: +; P8-NEXT: mflr r0 +; P8-NEXT: stdu r1, -32(r1) +; P8-NEXT: clrldi r3, r3, 48 +; P8-NEXT: std r0, 48(r1) +; P8-NEXT: bl __extendhfsf2 +; P8-NEXT: nop +; P8-NEXT: addi r1, r1, 32 +; P8-NEXT: ld r0, 16(r1) +; P8-NEXT: mtlr r0 +; P8-NEXT: blr +; +; P9-LABEL: extend_f16_to_f32: +; P9: # %bb.0: +; P9-NEXT: clrlwi r3, r3, 16 +; P9-NEXT: mtfprwz f0, r3 +; P9-NEXT: xscvhpdp f1, f0 +; P9-NEXT: blr + %r = fpext half %a to float + ret float %r +} + +; --------------------------------------------------------------------------- +; Truncate f32 -> f16 (soft: libcall on P8, hardware XSCVDPHP on P9) +; --------------------------------------------------------------------------- + +define half @trunc_f32_to_f16(float %a) nounwind { +; P8-LABEL: trunc_f32_to_f16: +; P8: # %bb.0: +; P8-NEXT: mflr r0 +; P8-NEXT: stdu r1, -32(r1) +; P8-NEXT: std r0, 48(r1) +; P8-NEXT: bl __truncsfhf2 +; P8-NEXT: nop +; P8-NEXT: addi r1, r1, 32 +; P8-NEXT: ld r0, 16(r1) +; P8-NEXT: mtlr r0 +; P8-NEXT: blr +; +; P9-LABEL: trunc_f32_to_f16: +; P9: # %bb.0: +; P9-NEXT: xscvdphp f0, f1 +; P9-NEXT: mffprwz r3, f0 +; P9-NEXT: blr + %r = fptrunc float %a to half + ret half %r +} + +; --------------------------------------------------------------------------- +; Extend load: f16 mem -> f64 (LXSIHZX+XSCVHPDP on P9) +; --------------------------------------------------------------------------- + +define double @extload_f16_to_f64(ptr %p) nounwind { +; P8-LABEL: extload_f16_to_f64: +; P8: # %bb.0: +; P8-NEXT: mflr r0 +; P8-NEXT: stdu r1, -32(r1) +; P8-NEXT: std r0, 48(r1) +; P8-NEXT: lhz r3, 0(r3) +; P8-NEXT: bl __extendhfsf2 +; P8-NEXT: nop +; P8-NEXT: addi r1, r1, 32 +; P8-NEXT: ld r0, 16(r1) +; P8-NEXT: mtlr r0 +; P8-NEXT: blr +; +; P9-LABEL: extload_f16_to_f64: +; P9: # %bb.0: +; P9-NEXT: lxsihzx f0, 0, r3 +; P9-NEXT: xscvhpdp f1, f0 +; P9-NEXT: blr + %v = load half, ptr %p + %r = fpext half %v to double + ret double %r +} + +; --------------------------------------------------------------------------- +; Truncate store: f64 -> f16 mem (XSCVDPHP+STXSIHX on P9) +; --------------------------------------------------------------------------- + +define void @truncstore_f64_to_f16(double %v, ptr %p) nounwind { +; P8-LABEL: truncstore_f64_to_f16: +; P8: # %bb.0: +; P8-NEXT: mflr r0 +; P8-NEXT: std r30, -16(r1) # 8-byte Folded Spill +; P8-NEXT: stdu r1, -48(r1) +; P8-NEXT: std r0, 64(r1) +; P8-NEXT: mr r30, r4 +; P8-NEXT: bl __truncdfhf2 +; P8-NEXT: nop +; P8-NEXT: sth r3, 0(r30) +; P8-NEXT: addi r1, r1, 48 +; P8-NEXT: ld r0, 16(r1) +; P8-NEXT: ld r30, -16(r1) # 8-byte Folded Reload +; P8-NEXT: mtlr r0 +; P8-NEXT: blr +; +; P9-LABEL: truncstore_f64_to_f16: +; P9: # %bb.0: +; P9-NEXT: xscvdphp f0, f1 +; P9-NEXT: stxsihx f0, 0, r4 +; P9-NEXT: blr + %t = fptrunc double %v to half + store half %t, ptr %p + ret void +} + +; --------------------------------------------------------------------------- +; Comparison: result is i1, operands promoted to f32 first +; --------------------------------------------------------------------------- + +define i1 @cmp_f16(half %a, half %b) nounwind { +; P8-LABEL: cmp_f16: +; P8: # %bb.0: +; P8-NEXT: mflr r0 +; P8-NEXT: std r30, -24(r1) # 8-byte Folded Spill +; P8-NEXT: stfd f31, -8(r1) # 8-byte Folded Spill +; P8-NEXT: stdu r1, -64(r1) +; P8-NEXT: mr r30, r3 +; P8-NEXT: clrldi r3, r4, 48 +; P8-NEXT: std r0, 80(r1) +; P8-NEXT: bl __extendhfsf2 +; P8-NEXT: nop +; P8-NEXT: clrldi r3, r30, 48 +; P8-NEXT: fmr f31, f1 +; P8-NEXT: bl __extendhfsf2 +; P8-NEXT: nop +; P8-NEXT: fcmpu cr0, f1, f31 +; P8-NEXT: li r3, 0 +; P8-NEXT: li r4, 1 +; P8-NEXT: isellt r3, r4, r3 +; P8-NEXT: addi r1, r1, 64 +; P8-NEXT: ld r0, 16(r1) +; P8-NEXT: lfd f31, -8(r1) # 8-byte Folded Reload +; P8-NEXT: ld r30, -24(r1) # 8-byte Folded Reload +; P8-NEXT: mtlr r0 +; P8-NEXT: blr +; +; P9-LABEL: cmp_f16: +; P9: # %bb.0: +; P9-NEXT: clrlwi r3, r3, 16 +; P9-NEXT: clrlwi r4, r4, 16 +; P9-NEXT: mtfprwz f0, r4 +; P9-NEXT: mtfprwz f1, r3 +; P9-NEXT: li r3, 0 +; P9-NEXT: li r4, 1 +; P9-NEXT: xscvhpdp f0, f0 +; P9-NEXT: xscvhpdp f1, f1 +; P9-NEXT: fcmpu cr0, f1, f0 +; P9-NEXT: isellt r3, r4, r3 +; P9-NEXT: blr + %r = fcmp olt half %a, %b + ret i1 %r +} + +; --------------------------------------------------------------------------- +; Integer to f16 conversion +; --------------------------------------------------------------------------- + +define half @sitofp_i32_to_f16(i32 %a) nounwind { +; P8-LABEL: sitofp_i32_to_f16: +; P8: # %bb.0: +; P8-NEXT: mflr r0 +; P8-NEXT: stdu r1, -32(r1) +; P8-NEXT: mtfprwa f0, r3 +; P8-NEXT: std r0, 48(r1) +; P8-NEXT: xscvsxdsp f1, f0 +; P8-NEXT: bl __truncsfhf2 +; P8-NEXT: nop +; P8-NEXT: addi r1, r1, 32 +; P8-NEXT: ld r0, 16(r1) +; P8-NEXT: mtlr r0 +; P8-NEXT: blr +; +; P9-LABEL: sitofp_i32_to_f16: +; P9: # %bb.0: +; P9-NEXT: mtfprwa f0, r3 +; P9-NEXT: xscvsxdsp f0, f0 +; P9-NEXT: xscvdphp f0, f0 +; P9-NEXT: mffprwz r3, f0 +; P9-NEXT: blr + %r = sitofp i32 %a to half + ret half %r +} `````````` </details> https://github.com/llvm/llvm-project/pull/208542 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
