Skip to content

Commit 5e778ed

Browse files
committed
[Xtensa] Add fp16 conversion support
Close espressif#91
1 parent dd37265 commit 5e778ed

2 files changed

Lines changed: 175 additions & 0 deletions

File tree

llvm/lib/Target/Xtensa/XtensaISelLowering.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
100100
setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i8, Expand);
101101
}
102102

103+
setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand);
104+
setOperationAction(ISD::FP_TO_FP16, MVT::f64, Expand);
105+
setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand);
106+
setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
107+
103108
setOperationAction(ISD::ConstantPool, PtrVT, Custom);
104109
setOperationAction(ISD::GlobalAddress, PtrVT, Custom);
105110
setOperationAction(ISD::GlobalTLSAddress, PtrVT, Custom);
@@ -244,8 +249,19 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
244249
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Expand);
245250
}
246251

252+
for (MVT VT : MVT::fp_valuetypes()) {
253+
setLoadExtAction(ISD::EXTLOAD, VT, MVT::f16, Expand);
254+
}
255+
256+
setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand);
257+
setOperationAction(ISD::FP_TO_FP16, MVT::f64, Expand);
258+
setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand);
259+
setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
260+
247261
// Floating-point truncation and stores need to be done separately.
248262
setTruncStoreAction(MVT::f64, MVT::f32, Expand);
263+
setTruncStoreAction(MVT::f64, MVT::f16, Expand);
264+
setTruncStoreAction(MVT::f32, MVT::f16, Expand);
249265

250266
if (Subtarget.hasS32C1I()) {
251267
setMaxAtomicSizeInBitsSupported(32);

llvm/test/CodeGen/Xtensa/fp16.ll

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
2+
; RUN: llc -mtriple=xtensa -mcpu=esp32 < %s | FileCheck --check-prefix=CHECK-ESP32 %s
3+
; RUN: llc -mtriple=xtensa -mcpu=esp32s2 < %s | FileCheck --check-prefix=CHECK-ESP32S2 %s
4+
5+
target datalayout = "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32"
6+
target triple = "xtensa"
7+
8+
@x = global i16 12902
9+
@y = global i16 0
10+
@z = common global i16 0
11+
12+
define void @foo() nounwind {
13+
; CHECK-ESP32-LABEL: foo:
14+
; CHECK-ESP32: # %bb.0: # %entry
15+
; CHECK-ESP32-NEXT: entry a1, 32
16+
; CHECK-ESP32-NEXT: l32r a6, .LCPI0_0
17+
; CHECK-ESP32-NEXT: l16ui a10, a6, 0
18+
; CHECK-ESP32-NEXT: l32r a8, .LCPI0_1
19+
; CHECK-ESP32-NEXT: callx8 a8
20+
; CHECK-ESP32-NEXT: or a7, a10, a10
21+
; CHECK-ESP32-NEXT: l32r a8, .LCPI0_2
22+
; CHECK-ESP32-NEXT: l16ui a10, a8, 0
23+
; CHECK-ESP32-NEXT: l32r a8, .LCPI0_3
24+
; CHECK-ESP32-NEXT: callx8 a8
25+
; CHECK-ESP32-NEXT: wfr f8, a10
26+
; CHECK-ESP32-NEXT: wfr f9, a7
27+
; CHECK-ESP32-NEXT: add.s f8, f9, f8
28+
; CHECK-ESP32-NEXT: rfr a10, f8
29+
; CHECK-ESP32-NEXT: l32r a8, .LCPI0_4
30+
; CHECK-ESP32-NEXT: callx8 a8
31+
; CHECK-ESP32-NEXT: s16i a10, a6, 0
32+
; CHECK-ESP32-NEXT: retw.n
33+
;
34+
; CHECK-ESP32S2-LABEL: foo:
35+
; CHECK-ESP32S2: # %bb.0: # %entry
36+
; CHECK-ESP32S2-NEXT: entry a1, 32
37+
; CHECK-ESP32S2-NEXT: l32r a6, .LCPI0_0
38+
; CHECK-ESP32S2-NEXT: l16ui a10, a6, 0
39+
; CHECK-ESP32S2-NEXT: l32r a8, .LCPI0_1
40+
; CHECK-ESP32S2-NEXT: callx8 a8
41+
; CHECK-ESP32S2-NEXT: or a7, a10, a10
42+
; CHECK-ESP32S2-NEXT: l32r a8, .LCPI0_2
43+
; CHECK-ESP32S2-NEXT: l16ui a10, a8, 0
44+
; CHECK-ESP32S2-NEXT: l32r a8, .LCPI0_3
45+
; CHECK-ESP32S2-NEXT: callx8 a8
46+
; CHECK-ESP32S2-NEXT: or a11, a10, a10
47+
; CHECK-ESP32S2-NEXT: l32r a8, .LCPI0_4
48+
; CHECK-ESP32S2-NEXT: or a10, a7, a7
49+
; CHECK-ESP32S2-NEXT: callx8 a8
50+
; CHECK-ESP32S2-NEXT: l32r a8, .LCPI0_5
51+
; CHECK-ESP32S2-NEXT: callx8 a8
52+
; CHECK-ESP32S2-NEXT: s16i a10, a6, 0
53+
; CHECK-ESP32S2-NEXT: retw.n
54+
entry:
55+
%0 = load i16, ptr @x, align 2
56+
%1 = load i16, ptr @y, align 2
57+
%2 = tail call float @llvm.convert.from.fp16.f32(i16 %0)
58+
%3 = tail call float @llvm.convert.from.fp16.f32(i16 %1)
59+
%4 = fadd float %2, %3
60+
%5 = tail call i16 @llvm.convert.to.fp16.f32(float %4)
61+
store i16 %5, ptr @x, align 2
62+
ret void
63+
}
64+
65+
define double @test_from_fp16(i16 %in) {
66+
; CHECK-ESP32-LABEL: test_from_fp16:
67+
; CHECK-ESP32: .cfi_startproc
68+
; CHECK-ESP32-NEXT: # %bb.0:
69+
; CHECK-ESP32-NEXT: entry a1, 32
70+
; CHECK-ESP32-NEXT: .cfi_def_cfa_offset 32
71+
; CHECK-ESP32-NEXT: or a10, a2, a2
72+
; CHECK-ESP32-NEXT: l32r a8, .LCPI1_0
73+
; CHECK-ESP32-NEXT: callx8 a8
74+
; CHECK-ESP32-NEXT: l32r a8, .LCPI1_1
75+
; CHECK-ESP32-NEXT: callx8 a8
76+
; CHECK-ESP32-NEXT: or a2, a10, a10
77+
; CHECK-ESP32-NEXT: or a3, a11, a11
78+
; CHECK-ESP32-NEXT: retw.n
79+
;
80+
; CHECK-ESP32S2-LABEL: test_from_fp16:
81+
; CHECK-ESP32S2: .cfi_startproc
82+
; CHECK-ESP32S2-NEXT: # %bb.0:
83+
; CHECK-ESP32S2-NEXT: entry a1, 32
84+
; CHECK-ESP32S2-NEXT: .cfi_def_cfa_offset 32
85+
; CHECK-ESP32S2-NEXT: l32r a8, .LCPI1_0
86+
; CHECK-ESP32S2-NEXT: and a10, a2, a8
87+
; CHECK-ESP32S2-NEXT: l32r a8, .LCPI1_1
88+
; CHECK-ESP32S2-NEXT: callx8 a8
89+
; CHECK-ESP32S2-NEXT: l32r a8, .LCPI1_2
90+
; CHECK-ESP32S2-NEXT: callx8 a8
91+
; CHECK-ESP32S2-NEXT: or a2, a10, a10
92+
; CHECK-ESP32S2-NEXT: or a3, a11, a11
93+
; CHECK-ESP32S2-NEXT: retw.n
94+
%val = call double @llvm.convert.from.fp16.f64(i16 %in)
95+
ret double %val
96+
}
97+
98+
define i16 @test_to_fp16(double %in) {
99+
; CHECK-ESP32-LABEL: test_to_fp16:
100+
; CHECK-ESP32: .cfi_startproc
101+
; CHECK-ESP32-NEXT: # %bb.0:
102+
; CHECK-ESP32-NEXT: entry a1, 32
103+
; CHECK-ESP32-NEXT: .cfi_def_cfa_offset 32
104+
; CHECK-ESP32-NEXT: or a11, a3, a3
105+
; CHECK-ESP32-NEXT: or a10, a2, a2
106+
; CHECK-ESP32-NEXT: l32r a8, .LCPI2_0
107+
; CHECK-ESP32-NEXT: callx8 a8
108+
; CHECK-ESP32-NEXT: or a2, a10, a10
109+
; CHECK-ESP32-NEXT: retw.n
110+
;
111+
; CHECK-ESP32S2-LABEL: test_to_fp16:
112+
; CHECK-ESP32S2: .cfi_startproc
113+
; CHECK-ESP32S2-NEXT: # %bb.0:
114+
; CHECK-ESP32S2-NEXT: entry a1, 32
115+
; CHECK-ESP32S2-NEXT: .cfi_def_cfa_offset 32
116+
; CHECK-ESP32S2-NEXT: or a11, a3, a3
117+
; CHECK-ESP32S2-NEXT: or a10, a2, a2
118+
; CHECK-ESP32S2-NEXT: l32r a8, .LCPI2_0
119+
; CHECK-ESP32S2-NEXT: callx8 a8
120+
; CHECK-ESP32S2-NEXT: or a2, a10, a10
121+
; CHECK-ESP32S2-NEXT: retw.n
122+
%val = call i16 @llvm.convert.to.fp16.f64(double %in)
123+
ret i16 %val
124+
}
125+
126+
; Function Attrs: nounwind
127+
define dso_local float @cvt(half %a) unnamed_addr #0 {
128+
; CHECK-ESP32-LABEL: cvt:
129+
; CHECK-ESP32: .cfi_startproc
130+
; CHECK-ESP32-NEXT: # %bb.0: # %start
131+
; CHECK-ESP32-NEXT: entry a1, 32
132+
; CHECK-ESP32-NEXT: .cfi_def_cfa_offset 32
133+
; CHECK-ESP32-NEXT: or a10, a2, a2
134+
; CHECK-ESP32-NEXT: l32r a8, .LCPI3_0
135+
; CHECK-ESP32-NEXT: callx8 a8
136+
; CHECK-ESP32-NEXT: or a2, a10, a10
137+
; CHECK-ESP32-NEXT: retw.n
138+
;
139+
; CHECK-ESP32S2-LABEL: cvt:
140+
; CHECK-ESP32S2: .cfi_startproc
141+
; CHECK-ESP32S2-NEXT: # %bb.0: # %start
142+
; CHECK-ESP32S2-NEXT: entry a1, 32
143+
; CHECK-ESP32S2-NEXT: .cfi_def_cfa_offset 32
144+
; CHECK-ESP32S2-NEXT: l32r a8, .LCPI3_0
145+
; CHECK-ESP32S2-NEXT: and a10, a2, a8
146+
; CHECK-ESP32S2-NEXT: l32r a8, .LCPI3_1
147+
; CHECK-ESP32S2-NEXT: callx8 a8
148+
; CHECK-ESP32S2-NEXT: or a2, a10, a10
149+
; CHECK-ESP32S2-NEXT: retw.n
150+
start:
151+
%_0 = fpext half %a to float
152+
ret float %_0
153+
}
154+
155+
declare float @llvm.convert.from.fp16.f32(i16) nounwind readnone
156+
declare double @llvm.convert.from.fp16.f64(i16) nounwind readnone
157+
158+
declare i16 @llvm.convert.to.fp16.f32(float) nounwind readnone
159+
declare i16 @llvm.convert.to.fp16.f64(double) nounwind readnone

0 commit comments

Comments
 (0)