https://github.com/dyung updated https://github.com/llvm/llvm-project/pull/212055
>From ca31b6cade94f9592f25fcf4c33634f7a27364ca Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov <[email protected]> Date: Wed, 22 Jul 2026 01:06:25 +0300 Subject: [PATCH] [Xtensa] Add fp16 conversion support (#208206) Close https://github.com/llvm/llvm-project/issues/207505 (cherry picked from commit db4d75e13ddc64cfb3a2f3620b622b8c4376812d) --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 11 ++ llvm/test/CodeGen/Xtensa/fp16.ll | 159 ++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 llvm/test/CodeGen/Xtensa/fp16.ll diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 0c880234af65f..09422cad222d1 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -244,8 +244,19 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM, setOperationAction(ISD::FP_TO_SINT, MVT::i32, Expand); } + for (MVT VT : MVT::fp_valuetypes()) { + setLoadExtAction(ISD::EXTLOAD, VT, MVT::f16, Expand); + } + + setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand); + setOperationAction(ISD::FP_TO_FP16, MVT::f64, Expand); + setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand); + setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand); + // Floating-point truncation and stores need to be done separately. setTruncStoreAction(MVT::f64, MVT::f32, Expand); + setTruncStoreAction(MVT::f64, MVT::f16, Expand); + setTruncStoreAction(MVT::f32, MVT::f16, Expand); if (Subtarget.hasS32C1I()) { setMaxAtomicSizeInBitsSupported(32); diff --git a/llvm/test/CodeGen/Xtensa/fp16.ll b/llvm/test/CodeGen/Xtensa/fp16.ll new file mode 100644 index 0000000000000..6ebc18ac8df08 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/fp16.ll @@ -0,0 +1,159 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2 +; RUN: llc -mtriple=xtensa -mcpu=esp32 < %s | FileCheck --check-prefix=CHECK-ESP32 %s +; RUN: llc -mtriple=xtensa -mcpu=esp32s2 < %s | FileCheck --check-prefix=CHECK-ESP32S2 %s + +target datalayout = "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32" +target triple = "xtensa" + +@x = global i16 12902 +@y = global i16 0 +@z = common global i16 0 + +define void @foo() nounwind { +; CHECK-ESP32-LABEL: foo: +; CHECK-ESP32: # %bb.0: # %entry +; CHECK-ESP32-NEXT: entry a1, 32 +; CHECK-ESP32-NEXT: l32r a6, .LCPI0_0 +; CHECK-ESP32-NEXT: l16ui a10, a6, 0 +; CHECK-ESP32-NEXT: l32r a8, .LCPI0_1 +; CHECK-ESP32-NEXT: callx8 a8 +; CHECK-ESP32-NEXT: or a7, a10, a10 +; CHECK-ESP32-NEXT: l32r a8, .LCPI0_2 +; CHECK-ESP32-NEXT: l16ui a10, a8, 0 +; CHECK-ESP32-NEXT: l32r a8, .LCPI0_3 +; CHECK-ESP32-NEXT: callx8 a8 +; CHECK-ESP32-NEXT: wfr f8, a10 +; CHECK-ESP32-NEXT: wfr f9, a7 +; CHECK-ESP32-NEXT: add.s f8, f9, f8 +; CHECK-ESP32-NEXT: rfr a10, f8 +; CHECK-ESP32-NEXT: l32r a8, .LCPI0_4 +; CHECK-ESP32-NEXT: callx8 a8 +; CHECK-ESP32-NEXT: s16i a10, a6, 0 +; CHECK-ESP32-NEXT: retw.n +; +; CHECK-ESP32S2-LABEL: foo: +; CHECK-ESP32S2: # %bb.0: # %entry +; CHECK-ESP32S2-NEXT: entry a1, 32 +; CHECK-ESP32S2-NEXT: l32r a6, .LCPI0_0 +; CHECK-ESP32S2-NEXT: l16ui a10, a6, 0 +; CHECK-ESP32S2-NEXT: l32r a8, .LCPI0_1 +; CHECK-ESP32S2-NEXT: callx8 a8 +; CHECK-ESP32S2-NEXT: or a7, a10, a10 +; CHECK-ESP32S2-NEXT: l32r a8, .LCPI0_2 +; CHECK-ESP32S2-NEXT: l16ui a10, a8, 0 +; CHECK-ESP32S2-NEXT: l32r a8, .LCPI0_3 +; CHECK-ESP32S2-NEXT: callx8 a8 +; CHECK-ESP32S2-NEXT: or a11, a10, a10 +; CHECK-ESP32S2-NEXT: l32r a8, .LCPI0_4 +; CHECK-ESP32S2-NEXT: or a10, a7, a7 +; CHECK-ESP32S2-NEXT: callx8 a8 +; CHECK-ESP32S2-NEXT: l32r a8, .LCPI0_5 +; CHECK-ESP32S2-NEXT: callx8 a8 +; CHECK-ESP32S2-NEXT: s16i a10, a6, 0 +; CHECK-ESP32S2-NEXT: retw.n +entry: + %fp16_v1 = load i16, ptr @x, align 2 + %fp16_v2 = load i16, ptr @y, align 2 + %f32_v1 = tail call float @llvm.convert.from.fp16.f32(i16 %fp16_v1) + %f32_v2 = tail call float @llvm.convert.from.fp16.f32(i16 %fp16_v2) + %f32_res = fadd float %f32_v1, %f32_v2 + %fp16_res = tail call i16 @llvm.convert.to.fp16.f32(float %f32_res) + store i16 %fp16_res, ptr @x, align 2 + ret void +} + +define double @test_from_fp16(i16 %in) { +; CHECK-ESP32-LABEL: test_from_fp16: +; CHECK-ESP32: .cfi_startproc +; CHECK-ESP32-NEXT: # %bb.0: +; CHECK-ESP32-NEXT: entry a1, 32 +; CHECK-ESP32-NEXT: .cfi_def_cfa_offset 32 +; CHECK-ESP32-NEXT: or a10, a2, a2 +; CHECK-ESP32-NEXT: l32r a8, .LCPI1_0 +; CHECK-ESP32-NEXT: callx8 a8 +; CHECK-ESP32-NEXT: l32r a8, .LCPI1_1 +; CHECK-ESP32-NEXT: callx8 a8 +; CHECK-ESP32-NEXT: or a2, a10, a10 +; CHECK-ESP32-NEXT: or a3, a11, a11 +; CHECK-ESP32-NEXT: retw.n +; +; CHECK-ESP32S2-LABEL: test_from_fp16: +; CHECK-ESP32S2: .cfi_startproc +; CHECK-ESP32S2-NEXT: # %bb.0: +; CHECK-ESP32S2-NEXT: entry a1, 32 +; CHECK-ESP32S2-NEXT: .cfi_def_cfa_offset 32 +; CHECK-ESP32S2-NEXT: l32r a8, .LCPI1_0 +; CHECK-ESP32S2-NEXT: and a10, a2, a8 +; CHECK-ESP32S2-NEXT: l32r a8, .LCPI1_1 +; CHECK-ESP32S2-NEXT: callx8 a8 +; CHECK-ESP32S2-NEXT: l32r a8, .LCPI1_2 +; CHECK-ESP32S2-NEXT: callx8 a8 +; CHECK-ESP32S2-NEXT: or a2, a10, a10 +; CHECK-ESP32S2-NEXT: or a3, a11, a11 +; CHECK-ESP32S2-NEXT: retw.n + %val = call double @llvm.convert.from.fp16.f64(i16 %in) + ret double %val +} + +define i16 @test_to_fp16(double %in) { +; CHECK-ESP32-LABEL: test_to_fp16: +; CHECK-ESP32: .cfi_startproc +; CHECK-ESP32-NEXT: # %bb.0: +; CHECK-ESP32-NEXT: entry a1, 32 +; CHECK-ESP32-NEXT: .cfi_def_cfa_offset 32 +; CHECK-ESP32-NEXT: or a11, a3, a3 +; CHECK-ESP32-NEXT: or a10, a2, a2 +; CHECK-ESP32-NEXT: l32r a8, .LCPI2_0 +; CHECK-ESP32-NEXT: callx8 a8 +; CHECK-ESP32-NEXT: or a2, a10, a10 +; CHECK-ESP32-NEXT: retw.n +; +; CHECK-ESP32S2-LABEL: test_to_fp16: +; CHECK-ESP32S2: .cfi_startproc +; CHECK-ESP32S2-NEXT: # %bb.0: +; CHECK-ESP32S2-NEXT: entry a1, 32 +; CHECK-ESP32S2-NEXT: .cfi_def_cfa_offset 32 +; CHECK-ESP32S2-NEXT: or a11, a3, a3 +; CHECK-ESP32S2-NEXT: or a10, a2, a2 +; CHECK-ESP32S2-NEXT: l32r a8, .LCPI2_0 +; CHECK-ESP32S2-NEXT: callx8 a8 +; CHECK-ESP32S2-NEXT: or a2, a10, a10 +; CHECK-ESP32S2-NEXT: retw.n + %val = call i16 @llvm.convert.to.fp16.f64(double %in) + ret i16 %val +} + +; Function Attrs: nounwind +define dso_local float @cvt(half %a) unnamed_addr #0 { +; CHECK-ESP32-LABEL: cvt: +; CHECK-ESP32: .cfi_startproc +; CHECK-ESP32-NEXT: # %bb.0: # %start +; CHECK-ESP32-NEXT: entry a1, 32 +; CHECK-ESP32-NEXT: .cfi_def_cfa_offset 32 +; CHECK-ESP32-NEXT: or a10, a2, a2 +; CHECK-ESP32-NEXT: l32r a8, .LCPI3_0 +; CHECK-ESP32-NEXT: callx8 a8 +; CHECK-ESP32-NEXT: or a2, a10, a10 +; CHECK-ESP32-NEXT: retw.n +; +; CHECK-ESP32S2-LABEL: cvt: +; CHECK-ESP32S2: .cfi_startproc +; CHECK-ESP32S2-NEXT: # %bb.0: # %start +; CHECK-ESP32S2-NEXT: entry a1, 32 +; CHECK-ESP32S2-NEXT: .cfi_def_cfa_offset 32 +; CHECK-ESP32S2-NEXT: l32r a8, .LCPI3_0 +; CHECK-ESP32S2-NEXT: and a10, a2, a8 +; CHECK-ESP32S2-NEXT: l32r a8, .LCPI3_1 +; CHECK-ESP32S2-NEXT: callx8 a8 +; CHECK-ESP32S2-NEXT: or a2, a10, a10 +; CHECK-ESP32S2-NEXT: retw.n +start: + %val = fpext half %a to float + ret float %val +} + +declare float @llvm.convert.from.fp16.f32(i16) nounwind readnone +declare double @llvm.convert.from.fp16.f64(i16) nounwind readnone + +declare i16 @llvm.convert.to.fp16.f32(float) nounwind readnone +declare i16 @llvm.convert.to.fp16.f64(double) nounwind readnone _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
