xref: /llvm-project/llvm/test/CodeGen/RISCV/half-bitmanip-dagcombines.ll (revision 9122c5235ec85ce0c0ad337e862b006e7b349d84)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
3; RUN:   | FileCheck -check-prefix=RV32I %s
4; RUN: llc -mtriple=riscv32 -target-abi ilp32 -mattr=+zfh -verify-machineinstrs \
5; RUN:   < %s | FileCheck -check-prefix=RV32IZFH %s
6; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
7; RUN:   | FileCheck -check-prefix=RV64I %s
8; RUN: llc -mtriple=riscv64 -target-abi lp64 -mattr=+zfh -verify-machineinstrs \
9; RUN:   < %s | FileCheck -check-prefix=RV64IZFH %s
10; RUN: llc -mtriple=riscv32 -target-abi ilp32 -mattr=+zhinx -verify-machineinstrs \
11; RUN:   < %s | FileCheck -check-prefix=RV32IZHINX %s
12; RUN: llc -mtriple=riscv64 -target-abi lp64 -mattr=+zhinx -verify-machineinstrs \
13; RUN:   < %s | FileCheck -check-prefix=RV64IZHINX %s
14; RUN: llc -mtriple=riscv32 -target-abi ilp32 -mattr=+zfhmin -verify-machineinstrs \
15; RUN:   < %s | FileCheck -check-prefix=RV32IZFHMIN %s
16; RUN: llc -mtriple=riscv64 -target-abi lp64 -verify-machineinstrs < %s \
17; RUN:   | FileCheck -check-prefix=RV64I %s
18; RUN: llc -mtriple=riscv64 -target-abi lp64 -mattr=+zfhmin -verify-machineinstrs \
19; RUN:   < %s | FileCheck -check-prefix=RV64IZFHMIN %s
20; RUN: llc -mtriple=riscv32 -target-abi ilp32 -mattr=+zhinxmin -verify-machineinstrs \
21; RUN:   < %s | FileCheck --check-prefixes=RVIZHINXMIN,RV32IZHINXMIN %s
22; RUN: llc -mtriple=riscv64 -target-abi lp64 -mattr=+zhinxmin -verify-machineinstrs \
23; RUN:   < %s | FileCheck --check-prefixes=RVIZHINXMIN,RV64IZHINXMIN %s
24
25; This file tests cases where simple floating point operations can be
26; profitably handled though bit manipulation if a soft-float ABI is being used
27; (e.g. fneg implemented by XORing the sign bit). This is typically handled in
28; DAGCombiner::visitBITCAST, but this target-independent code may not trigger
29; in cases where we perform custom legalisation (e.g. RV64F).
30
31define half @fneg(half %a) nounwind {
32; RV32I-LABEL: fneg:
33; RV32I:       # %bb.0:
34; RV32I-NEXT:    lui a1, 1048568
35; RV32I-NEXT:    xor a0, a0, a1
36; RV32I-NEXT:    ret
37;
38; RV32IZFH-LABEL: fneg:
39; RV32IZFH:       # %bb.0:
40; RV32IZFH-NEXT:    lui a1, 1048568
41; RV32IZFH-NEXT:    xor a0, a0, a1
42; RV32IZFH-NEXT:    ret
43;
44; RV64I-LABEL: fneg:
45; RV64I:       # %bb.0:
46; RV64I-NEXT:    lui a1, 1048568
47; RV64I-NEXT:    xor a0, a0, a1
48; RV64I-NEXT:    ret
49;
50; RV64IZFH-LABEL: fneg:
51; RV64IZFH:       # %bb.0:
52; RV64IZFH-NEXT:    lui a1, 1048568
53; RV64IZFH-NEXT:    xor a0, a0, a1
54; RV64IZFH-NEXT:    ret
55;
56; RV32IZHINX-LABEL: fneg:
57; RV32IZHINX:       # %bb.0:
58; RV32IZHINX-NEXT:    fneg.h a0, a0
59; RV32IZHINX-NEXT:    ret
60;
61; RV64IZHINX-LABEL: fneg:
62; RV64IZHINX:       # %bb.0:
63; RV64IZHINX-NEXT:    fneg.h a0, a0
64; RV64IZHINX-NEXT:    ret
65;
66; RV32IZFHMIN-LABEL: fneg:
67; RV32IZFHMIN:       # %bb.0:
68; RV32IZFHMIN-NEXT:    lui a1, 1048568
69; RV32IZFHMIN-NEXT:    xor a0, a0, a1
70; RV32IZFHMIN-NEXT:    ret
71;
72; RV64IZFHMIN-LABEL: fneg:
73; RV64IZFHMIN:       # %bb.0:
74; RV64IZFHMIN-NEXT:    lui a1, 1048568
75; RV64IZFHMIN-NEXT:    xor a0, a0, a1
76; RV64IZFHMIN-NEXT:    ret
77;
78; RVIZHINXMIN-LABEL: fneg:
79; RVIZHINXMIN:       # %bb.0:
80; RVIZHINXMIN-NEXT:    # kill: def $x10_h killed $x10_h def $x10
81; RVIZHINXMIN-NEXT:    lui a1, 1048568
82; RVIZHINXMIN-NEXT:    xor a0, a0, a1
83; RVIZHINXMIN-NEXT:    # kill: def $x10_h killed $x10_h killed $x10
84; RVIZHINXMIN-NEXT:    ret
85  %1 = fneg half %a
86  ret half %1
87}
88
89declare half @llvm.fabs.f16(half)
90
91define half @fabs(half %a) nounwind {
92; RV32I-LABEL: fabs:
93; RV32I:       # %bb.0:
94; RV32I-NEXT:    slli a0, a0, 17
95; RV32I-NEXT:    srli a0, a0, 17
96; RV32I-NEXT:    ret
97;
98; RV32IZFH-LABEL: fabs:
99; RV32IZFH:       # %bb.0:
100; RV32IZFH-NEXT:    slli a0, a0, 17
101; RV32IZFH-NEXT:    srli a0, a0, 17
102; RV32IZFH-NEXT:    ret
103;
104; RV64I-LABEL: fabs:
105; RV64I:       # %bb.0:
106; RV64I-NEXT:    slli a0, a0, 49
107; RV64I-NEXT:    srli a0, a0, 49
108; RV64I-NEXT:    ret
109;
110; RV64IZFH-LABEL: fabs:
111; RV64IZFH:       # %bb.0:
112; RV64IZFH-NEXT:    slli a0, a0, 49
113; RV64IZFH-NEXT:    srli a0, a0, 49
114; RV64IZFH-NEXT:    ret
115;
116; RV32IZHINX-LABEL: fabs:
117; RV32IZHINX:       # %bb.0:
118; RV32IZHINX-NEXT:    fabs.h a0, a0
119; RV32IZHINX-NEXT:    ret
120;
121; RV64IZHINX-LABEL: fabs:
122; RV64IZHINX:       # %bb.0:
123; RV64IZHINX-NEXT:    fabs.h a0, a0
124; RV64IZHINX-NEXT:    ret
125;
126; RV32IZFHMIN-LABEL: fabs:
127; RV32IZFHMIN:       # %bb.0:
128; RV32IZFHMIN-NEXT:    slli a0, a0, 17
129; RV32IZFHMIN-NEXT:    srli a0, a0, 17
130; RV32IZFHMIN-NEXT:    ret
131;
132; RV64IZFHMIN-LABEL: fabs:
133; RV64IZFHMIN:       # %bb.0:
134; RV64IZFHMIN-NEXT:    slli a0, a0, 49
135; RV64IZFHMIN-NEXT:    srli a0, a0, 49
136; RV64IZFHMIN-NEXT:    ret
137;
138; RV32IZHINXMIN-LABEL: fabs:
139; RV32IZHINXMIN:       # %bb.0:
140; RV32IZHINXMIN-NEXT:    # kill: def $x10_h killed $x10_h def $x10
141; RV32IZHINXMIN-NEXT:    slli a0, a0, 17
142; RV32IZHINXMIN-NEXT:    srli a0, a0, 17
143; RV32IZHINXMIN-NEXT:    # kill: def $x10_h killed $x10_h killed $x10
144; RV32IZHINXMIN-NEXT:    ret
145;
146; RV64IZHINXMIN-LABEL: fabs:
147; RV64IZHINXMIN:       # %bb.0:
148; RV64IZHINXMIN-NEXT:    # kill: def $x10_h killed $x10_h def $x10
149; RV64IZHINXMIN-NEXT:    slli a0, a0, 49
150; RV64IZHINXMIN-NEXT:    srli a0, a0, 49
151; RV64IZHINXMIN-NEXT:    # kill: def $x10_h killed $x10_h killed $x10
152; RV64IZHINXMIN-NEXT:    ret
153  %1 = call half @llvm.fabs.f16(half %a)
154  ret half %1
155}
156
157declare half @llvm.copysign.f16(half, half)
158
159; DAGTypeLegalizer::SoftenFloatRes_FCOPYSIGN will convert to bitwise
160; operations if half precision floating point isn't supported. A combine could
161; be written to do the same even when f16 is legal.
162
163define half @fcopysign_fneg(half %a, half %b) nounwind {
164; RV32I-LABEL: fcopysign_fneg:
165; RV32I:       # %bb.0:
166; RV32I-NEXT:    not a1, a1
167; RV32I-NEXT:    lui a2, 1048568
168; RV32I-NEXT:    slli a0, a0, 17
169; RV32I-NEXT:    and a1, a1, a2
170; RV32I-NEXT:    srli a0, a0, 17
171; RV32I-NEXT:    or a0, a0, a1
172; RV32I-NEXT:    ret
173;
174; RV32IZFH-LABEL: fcopysign_fneg:
175; RV32IZFH:       # %bb.0:
176; RV32IZFH-NEXT:    fmv.h.x fa5, a1
177; RV32IZFH-NEXT:    fmv.h.x fa4, a0
178; RV32IZFH-NEXT:    fsgnjn.h fa5, fa4, fa5
179; RV32IZFH-NEXT:    fmv.x.h a0, fa5
180; RV32IZFH-NEXT:    ret
181;
182; RV64I-LABEL: fcopysign_fneg:
183; RV64I:       # %bb.0:
184; RV64I-NEXT:    not a1, a1
185; RV64I-NEXT:    lui a2, 1048568
186; RV64I-NEXT:    slli a0, a0, 49
187; RV64I-NEXT:    and a1, a1, a2
188; RV64I-NEXT:    srli a0, a0, 49
189; RV64I-NEXT:    or a0, a0, a1
190; RV64I-NEXT:    ret
191;
192; RV64IZFH-LABEL: fcopysign_fneg:
193; RV64IZFH:       # %bb.0:
194; RV64IZFH-NEXT:    fmv.h.x fa5, a1
195; RV64IZFH-NEXT:    fmv.h.x fa4, a0
196; RV64IZFH-NEXT:    fsgnjn.h fa5, fa4, fa5
197; RV64IZFH-NEXT:    fmv.x.h a0, fa5
198; RV64IZFH-NEXT:    ret
199;
200; RV32IZHINX-LABEL: fcopysign_fneg:
201; RV32IZHINX:       # %bb.0:
202; RV32IZHINX-NEXT:    fsgnjn.h a0, a0, a1
203; RV32IZHINX-NEXT:    ret
204;
205; RV64IZHINX-LABEL: fcopysign_fneg:
206; RV64IZHINX:       # %bb.0:
207; RV64IZHINX-NEXT:    fsgnjn.h a0, a0, a1
208; RV64IZHINX-NEXT:    ret
209;
210; RV32IZFHMIN-LABEL: fcopysign_fneg:
211; RV32IZFHMIN:       # %bb.0:
212; RV32IZFHMIN-NEXT:    not a1, a1
213; RV32IZFHMIN-NEXT:    lui a2, 1048568
214; RV32IZFHMIN-NEXT:    slli a0, a0, 17
215; RV32IZFHMIN-NEXT:    and a1, a1, a2
216; RV32IZFHMIN-NEXT:    srli a0, a0, 17
217; RV32IZFHMIN-NEXT:    or a0, a0, a1
218; RV32IZFHMIN-NEXT:    ret
219;
220; RV64IZFHMIN-LABEL: fcopysign_fneg:
221; RV64IZFHMIN:       # %bb.0:
222; RV64IZFHMIN-NEXT:    not a1, a1
223; RV64IZFHMIN-NEXT:    lui a2, 1048568
224; RV64IZFHMIN-NEXT:    slli a0, a0, 49
225; RV64IZFHMIN-NEXT:    and a1, a1, a2
226; RV64IZFHMIN-NEXT:    srli a0, a0, 49
227; RV64IZFHMIN-NEXT:    or a0, a0, a1
228; RV64IZFHMIN-NEXT:    ret
229;
230; RV32IZHINXMIN-LABEL: fcopysign_fneg:
231; RV32IZHINXMIN:       # %bb.0:
232; RV32IZHINXMIN-NEXT:    # kill: def $x11_h killed $x11_h def $x11
233; RV32IZHINXMIN-NEXT:    # kill: def $x10_h killed $x10_h def $x10
234; RV32IZHINXMIN-NEXT:    not a1, a1
235; RV32IZHINXMIN-NEXT:    lui a2, 1048568
236; RV32IZHINXMIN-NEXT:    slli a0, a0, 17
237; RV32IZHINXMIN-NEXT:    and a1, a1, a2
238; RV32IZHINXMIN-NEXT:    srli a0, a0, 17
239; RV32IZHINXMIN-NEXT:    or a0, a0, a1
240; RV32IZHINXMIN-NEXT:    # kill: def $x10_h killed $x10_h killed $x10
241; RV32IZHINXMIN-NEXT:    ret
242;
243; RV64IZHINXMIN-LABEL: fcopysign_fneg:
244; RV64IZHINXMIN:       # %bb.0:
245; RV64IZHINXMIN-NEXT:    # kill: def $x11_h killed $x11_h def $x11
246; RV64IZHINXMIN-NEXT:    # kill: def $x10_h killed $x10_h def $x10
247; RV64IZHINXMIN-NEXT:    not a1, a1
248; RV64IZHINXMIN-NEXT:    lui a2, 1048568
249; RV64IZHINXMIN-NEXT:    slli a0, a0, 49
250; RV64IZHINXMIN-NEXT:    and a1, a1, a2
251; RV64IZHINXMIN-NEXT:    srli a0, a0, 49
252; RV64IZHINXMIN-NEXT:    or a0, a0, a1
253; RV64IZHINXMIN-NEXT:    # kill: def $x10_h killed $x10_h killed $x10
254; RV64IZHINXMIN-NEXT:    ret
255  %1 = fneg half %b
256  %2 = call half @llvm.copysign.f16(half %a, half %1)
257  ret half %2
258}
259