1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \
3; RUN:   | FileCheck -check-prefix=RV32F %s
4; RUN: llc -mtriple=riscv32 -mattr=+f,+d -verify-machineinstrs < %s \
5; RUN:   | FileCheck -check-prefix=RV32FD %s
6; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s \
7; RUN:   | FileCheck -check-prefix=RV64F %s
8; RUN: llc -mtriple=riscv64 -mattr=+f,+d -verify-machineinstrs < %s \
9; RUN:   | FileCheck -check-prefix=RV64FD %s
10
11; These functions perform extra work to ensure that `%a3` starts in a
12; floating-point register, if the machine has them, and the result of
13; the bitwise operation is then needed in a floating-point register.
14; This should mean the optimisations will fire even if you're using the
15; soft-float ABI on a machine with hardware floating-point support.
16
17define float @bitcast_and(float %a1, float %a2) nounwind {
18; RV32F-LABEL: bitcast_and:
19; RV32F:       # %bb.0:
20; RV32F-NEXT:    fmv.w.x ft0, a1
21; RV32F-NEXT:    fmv.w.x ft1, a0
22; RV32F-NEXT:    fadd.s ft0, ft1, ft0
23; RV32F-NEXT:    fabs.s ft0, ft0
24; RV32F-NEXT:    fadd.s ft0, ft1, ft0
25; RV32F-NEXT:    fmv.x.w a0, ft0
26; RV32F-NEXT:    ret
27;
28; RV32FD-LABEL: bitcast_and:
29; RV32FD:       # %bb.0:
30; RV32FD-NEXT:    fmv.w.x ft0, a1
31; RV32FD-NEXT:    fmv.w.x ft1, a0
32; RV32FD-NEXT:    fadd.s ft0, ft1, ft0
33; RV32FD-NEXT:    fabs.s ft0, ft0
34; RV32FD-NEXT:    fadd.s ft0, ft1, ft0
35; RV32FD-NEXT:    fmv.x.w a0, ft0
36; RV32FD-NEXT:    ret
37;
38; RV64F-LABEL: bitcast_and:
39; RV64F:       # %bb.0:
40; RV64F-NEXT:    fmv.w.x ft0, a1
41; RV64F-NEXT:    fmv.w.x ft1, a0
42; RV64F-NEXT:    fadd.s ft0, ft1, ft0
43; RV64F-NEXT:    fabs.s ft0, ft0
44; RV64F-NEXT:    fadd.s ft0, ft1, ft0
45; RV64F-NEXT:    fmv.x.w a0, ft0
46; RV64F-NEXT:    ret
47;
48; RV64FD-LABEL: bitcast_and:
49; RV64FD:       # %bb.0:
50; RV64FD-NEXT:    fmv.w.x ft0, a1
51; RV64FD-NEXT:    fmv.w.x ft1, a0
52; RV64FD-NEXT:    fadd.s ft0, ft1, ft0
53; RV64FD-NEXT:    fabs.s ft0, ft0
54; RV64FD-NEXT:    fadd.s ft0, ft1, ft0
55; RV64FD-NEXT:    fmv.x.w a0, ft0
56; RV64FD-NEXT:    ret
57  %a3 = fadd float %a1, %a2
58  %bc1 = bitcast float %a3 to i32
59  %and = and i32 %bc1, 2147483647
60  %bc2 = bitcast i32 %and to float
61  %a4 = fadd float %a1, %bc2
62  ret float %a4
63}
64
65define double @bitcast_double_and(double %a1, double %a2) nounwind {
66; RV32F-LABEL: bitcast_double_and:
67; RV32F:       # %bb.0:
68; RV32F-NEXT:    addi sp, sp, -16
69; RV32F-NEXT:    sw ra, 12(sp)
70; RV32F-NEXT:    sw s0, 8(sp)
71; RV32F-NEXT:    sw s1, 4(sp)
72; RV32F-NEXT:    mv s0, a1
73; RV32F-NEXT:    mv s1, a0
74; RV32F-NEXT:    call __adddf3
75; RV32F-NEXT:    mv a2, a0
76; RV32F-NEXT:    lui a0, 524288
77; RV32F-NEXT:    addi a0, a0, -1
78; RV32F-NEXT:    and a3, a1, a0
79; RV32F-NEXT:    mv a0, s1
80; RV32F-NEXT:    mv a1, s0
81; RV32F-NEXT:    call __adddf3
82; RV32F-NEXT:    lw s1, 4(sp)
83; RV32F-NEXT:    lw s0, 8(sp)
84; RV32F-NEXT:    lw ra, 12(sp)
85; RV32F-NEXT:    addi sp, sp, 16
86; RV32F-NEXT:    ret
87;
88; RV32FD-LABEL: bitcast_double_and:
89; RV32FD:       # %bb.0:
90; RV32FD-NEXT:    addi sp, sp, -16
91; RV32FD-NEXT:    sw a2, 8(sp)
92; RV32FD-NEXT:    sw a3, 12(sp)
93; RV32FD-NEXT:    fld ft0, 8(sp)
94; RV32FD-NEXT:    sw a0, 8(sp)
95; RV32FD-NEXT:    sw a1, 12(sp)
96; RV32FD-NEXT:    fld ft1, 8(sp)
97; RV32FD-NEXT:    fadd.d ft0, ft1, ft0
98; RV32FD-NEXT:    fabs.d ft0, ft0
99; RV32FD-NEXT:    fadd.d ft0, ft1, ft0
100; RV32FD-NEXT:    fsd ft0, 8(sp)
101; RV32FD-NEXT:    lw a0, 8(sp)
102; RV32FD-NEXT:    lw a1, 12(sp)
103; RV32FD-NEXT:    addi sp, sp, 16
104; RV32FD-NEXT:    ret
105;
106; RV64F-LABEL: bitcast_double_and:
107; RV64F:       # %bb.0:
108; RV64F-NEXT:    addi sp, sp, -16
109; RV64F-NEXT:    sd ra, 8(sp)
110; RV64F-NEXT:    sd s0, 0(sp)
111; RV64F-NEXT:    mv s0, a0
112; RV64F-NEXT:    call __adddf3
113; RV64F-NEXT:    addi a1, zero, -1
114; RV64F-NEXT:    slli a1, a1, 63
115; RV64F-NEXT:    addi a1, a1, -1
116; RV64F-NEXT:    and a1, a0, a1
117; RV64F-NEXT:    mv a0, s0
118; RV64F-NEXT:    call __adddf3
119; RV64F-NEXT:    ld s0, 0(sp)
120; RV64F-NEXT:    ld ra, 8(sp)
121; RV64F-NEXT:    addi sp, sp, 16
122; RV64F-NEXT:    ret
123;
124; RV64FD-LABEL: bitcast_double_and:
125; RV64FD:       # %bb.0:
126; RV64FD-NEXT:    fmv.d.x ft0, a1
127; RV64FD-NEXT:    fmv.d.x ft1, a0
128; RV64FD-NEXT:    fadd.d ft0, ft1, ft0
129; RV64FD-NEXT:    fabs.d ft0, ft0
130; RV64FD-NEXT:    fadd.d ft0, ft1, ft0
131; RV64FD-NEXT:    fmv.x.d a0, ft0
132; RV64FD-NEXT:    ret
133  %a3 = fadd double %a1, %a2
134  %bc1 = bitcast double %a3 to i64
135  %and = and i64 %bc1, 9223372036854775807
136  %bc2 = bitcast i64 %and to double
137  %a4 = fadd double %a1, %bc2
138  ret double %a4
139}
140
141
142define float @bitcast_xor(float %a1, float %a2) nounwind {
143; RV32F-LABEL: bitcast_xor:
144; RV32F:       # %bb.0:
145; RV32F-NEXT:    fmv.w.x ft0, a1
146; RV32F-NEXT:    fmv.w.x ft1, a0
147; RV32F-NEXT:    fmul.s ft0, ft1, ft0
148; RV32F-NEXT:    fneg.s ft0, ft0
149; RV32F-NEXT:    fmul.s ft0, ft1, ft0
150; RV32F-NEXT:    fmv.x.w a0, ft0
151; RV32F-NEXT:    ret
152;
153; RV32FD-LABEL: bitcast_xor:
154; RV32FD:       # %bb.0:
155; RV32FD-NEXT:    fmv.w.x ft0, a1
156; RV32FD-NEXT:    fmv.w.x ft1, a0
157; RV32FD-NEXT:    fmul.s ft0, ft1, ft0
158; RV32FD-NEXT:    fneg.s ft0, ft0
159; RV32FD-NEXT:    fmul.s ft0, ft1, ft0
160; RV32FD-NEXT:    fmv.x.w a0, ft0
161; RV32FD-NEXT:    ret
162;
163; RV64F-LABEL: bitcast_xor:
164; RV64F:       # %bb.0:
165; RV64F-NEXT:    fmv.w.x ft0, a1
166; RV64F-NEXT:    fmv.w.x ft1, a0
167; RV64F-NEXT:    fmul.s ft0, ft1, ft0
168; RV64F-NEXT:    fneg.s ft0, ft0
169; RV64F-NEXT:    fmul.s ft0, ft1, ft0
170; RV64F-NEXT:    fmv.x.w a0, ft0
171; RV64F-NEXT:    ret
172;
173; RV64FD-LABEL: bitcast_xor:
174; RV64FD:       # %bb.0:
175; RV64FD-NEXT:    fmv.w.x ft0, a1
176; RV64FD-NEXT:    fmv.w.x ft1, a0
177; RV64FD-NEXT:    fmul.s ft0, ft1, ft0
178; RV64FD-NEXT:    fneg.s ft0, ft0
179; RV64FD-NEXT:    fmul.s ft0, ft1, ft0
180; RV64FD-NEXT:    fmv.x.w a0, ft0
181; RV64FD-NEXT:    ret
182  %a3 = fmul float %a1, %a2
183  %bc1 = bitcast float %a3 to i32
184  %and = xor i32 %bc1, 2147483648
185  %bc2 = bitcast i32 %and to float
186  %a4 = fmul float %a1, %bc2
187  ret float %a4
188}
189
190define double @bitcast_double_xor(double %a1, double %a2) nounwind {
191; RV32F-LABEL: bitcast_double_xor:
192; RV32F:       # %bb.0:
193; RV32F-NEXT:    addi sp, sp, -16
194; RV32F-NEXT:    sw ra, 12(sp)
195; RV32F-NEXT:    sw s0, 8(sp)
196; RV32F-NEXT:    sw s1, 4(sp)
197; RV32F-NEXT:    mv s0, a1
198; RV32F-NEXT:    mv s1, a0
199; RV32F-NEXT:    call __muldf3
200; RV32F-NEXT:    mv a2, a0
201; RV32F-NEXT:    lui a0, 524288
202; RV32F-NEXT:    xor a3, a1, a0
203; RV32F-NEXT:    mv a0, s1
204; RV32F-NEXT:    mv a1, s0
205; RV32F-NEXT:    call __muldf3
206; RV32F-NEXT:    lw s1, 4(sp)
207; RV32F-NEXT:    lw s0, 8(sp)
208; RV32F-NEXT:    lw ra, 12(sp)
209; RV32F-NEXT:    addi sp, sp, 16
210; RV32F-NEXT:    ret
211;
212; RV32FD-LABEL: bitcast_double_xor:
213; RV32FD:       # %bb.0:
214; RV32FD-NEXT:    addi sp, sp, -16
215; RV32FD-NEXT:    sw a2, 8(sp)
216; RV32FD-NEXT:    sw a3, 12(sp)
217; RV32FD-NEXT:    fld ft0, 8(sp)
218; RV32FD-NEXT:    sw a0, 8(sp)
219; RV32FD-NEXT:    sw a1, 12(sp)
220; RV32FD-NEXT:    fld ft1, 8(sp)
221; RV32FD-NEXT:    fmul.d ft0, ft1, ft0
222; RV32FD-NEXT:    fneg.d ft0, ft0
223; RV32FD-NEXT:    fmul.d ft0, ft1, ft0
224; RV32FD-NEXT:    fsd ft0, 8(sp)
225; RV32FD-NEXT:    lw a0, 8(sp)
226; RV32FD-NEXT:    lw a1, 12(sp)
227; RV32FD-NEXT:    addi sp, sp, 16
228; RV32FD-NEXT:    ret
229;
230; RV64F-LABEL: bitcast_double_xor:
231; RV64F:       # %bb.0:
232; RV64F-NEXT:    addi sp, sp, -16
233; RV64F-NEXT:    sd ra, 8(sp)
234; RV64F-NEXT:    sd s0, 0(sp)
235; RV64F-NEXT:    mv s0, a0
236; RV64F-NEXT:    call __muldf3
237; RV64F-NEXT:    addi a1, zero, -1
238; RV64F-NEXT:    slli a1, a1, 63
239; RV64F-NEXT:    xor a1, a0, a1
240; RV64F-NEXT:    mv a0, s0
241; RV64F-NEXT:    call __muldf3
242; RV64F-NEXT:    ld s0, 0(sp)
243; RV64F-NEXT:    ld ra, 8(sp)
244; RV64F-NEXT:    addi sp, sp, 16
245; RV64F-NEXT:    ret
246;
247; RV64FD-LABEL: bitcast_double_xor:
248; RV64FD:       # %bb.0:
249; RV64FD-NEXT:    fmv.d.x ft0, a1
250; RV64FD-NEXT:    fmv.d.x ft1, a0
251; RV64FD-NEXT:    fmul.d ft0, ft1, ft0
252; RV64FD-NEXT:    fneg.d ft0, ft0
253; RV64FD-NEXT:    fmul.d ft0, ft1, ft0
254; RV64FD-NEXT:    fmv.x.d a0, ft0
255; RV64FD-NEXT:    ret
256  %a3 = fmul double %a1, %a2
257  %bc1 = bitcast double %a3 to i64
258  %and = xor i64 %bc1, 9223372036854775808
259  %bc2 = bitcast i64 %and to double
260  %a4 = fmul double %a1, %bc2
261  ret double %a4
262}
263
264define float @bitcast_or(float %a1, float %a2) nounwind {
265; RV32F-LABEL: bitcast_or:
266; RV32F:       # %bb.0:
267; RV32F-NEXT:    fmv.w.x ft0, a1
268; RV32F-NEXT:    fmv.w.x ft1, a0
269; RV32F-NEXT:    fmul.s ft0, ft1, ft0
270; RV32F-NEXT:    fabs.s ft0, ft0
271; RV32F-NEXT:    fneg.s ft0, ft0
272; RV32F-NEXT:    fmul.s ft0, ft1, ft0
273; RV32F-NEXT:    fmv.x.w a0, ft0
274; RV32F-NEXT:    ret
275;
276; RV32FD-LABEL: bitcast_or:
277; RV32FD:       # %bb.0:
278; RV32FD-NEXT:    fmv.w.x ft0, a1
279; RV32FD-NEXT:    fmv.w.x ft1, a0
280; RV32FD-NEXT:    fmul.s ft0, ft1, ft0
281; RV32FD-NEXT:    fabs.s ft0, ft0
282; RV32FD-NEXT:    fneg.s ft0, ft0
283; RV32FD-NEXT:    fmul.s ft0, ft1, ft0
284; RV32FD-NEXT:    fmv.x.w a0, ft0
285; RV32FD-NEXT:    ret
286;
287; RV64F-LABEL: bitcast_or:
288; RV64F:       # %bb.0:
289; RV64F-NEXT:    fmv.w.x ft0, a1
290; RV64F-NEXT:    fmv.w.x ft1, a0
291; RV64F-NEXT:    fmul.s ft0, ft1, ft0
292; RV64F-NEXT:    fabs.s ft0, ft0
293; RV64F-NEXT:    fneg.s ft0, ft0
294; RV64F-NEXT:    fmul.s ft0, ft1, ft0
295; RV64F-NEXT:    fmv.x.w a0, ft0
296; RV64F-NEXT:    ret
297;
298; RV64FD-LABEL: bitcast_or:
299; RV64FD:       # %bb.0:
300; RV64FD-NEXT:    fmv.w.x ft0, a1
301; RV64FD-NEXT:    fmv.w.x ft1, a0
302; RV64FD-NEXT:    fmul.s ft0, ft1, ft0
303; RV64FD-NEXT:    fabs.s ft0, ft0
304; RV64FD-NEXT:    fneg.s ft0, ft0
305; RV64FD-NEXT:    fmul.s ft0, ft1, ft0
306; RV64FD-NEXT:    fmv.x.w a0, ft0
307; RV64FD-NEXT:    ret
308  %a3 = fmul float %a1, %a2
309  %bc1 = bitcast float %a3 to i32
310  %and = or i32 %bc1, 2147483648
311  %bc2 = bitcast i32 %and to float
312  %a4 = fmul float %a1, %bc2
313  ret float %a4
314}
315
316define double @bitcast_double_or(double %a1, double %a2) nounwind {
317; RV32F-LABEL: bitcast_double_or:
318; RV32F:       # %bb.0:
319; RV32F-NEXT:    addi sp, sp, -16
320; RV32F-NEXT:    sw ra, 12(sp)
321; RV32F-NEXT:    sw s0, 8(sp)
322; RV32F-NEXT:    sw s1, 4(sp)
323; RV32F-NEXT:    mv s0, a1
324; RV32F-NEXT:    mv s1, a0
325; RV32F-NEXT:    call __muldf3
326; RV32F-NEXT:    mv a2, a0
327; RV32F-NEXT:    lui a0, 524288
328; RV32F-NEXT:    or a3, a1, a0
329; RV32F-NEXT:    mv a0, s1
330; RV32F-NEXT:    mv a1, s0
331; RV32F-NEXT:    call __muldf3
332; RV32F-NEXT:    lw s1, 4(sp)
333; RV32F-NEXT:    lw s0, 8(sp)
334; RV32F-NEXT:    lw ra, 12(sp)
335; RV32F-NEXT:    addi sp, sp, 16
336; RV32F-NEXT:    ret
337;
338; RV32FD-LABEL: bitcast_double_or:
339; RV32FD:       # %bb.0:
340; RV32FD-NEXT:    addi sp, sp, -16
341; RV32FD-NEXT:    sw a2, 8(sp)
342; RV32FD-NEXT:    sw a3, 12(sp)
343; RV32FD-NEXT:    fld ft0, 8(sp)
344; RV32FD-NEXT:    sw a0, 8(sp)
345; RV32FD-NEXT:    sw a1, 12(sp)
346; RV32FD-NEXT:    fld ft1, 8(sp)
347; RV32FD-NEXT:    fmul.d ft0, ft1, ft0
348; RV32FD-NEXT:    fabs.d ft0, ft0
349; RV32FD-NEXT:    fneg.d ft0, ft0
350; RV32FD-NEXT:    fmul.d ft0, ft1, ft0
351; RV32FD-NEXT:    fsd ft0, 8(sp)
352; RV32FD-NEXT:    lw a0, 8(sp)
353; RV32FD-NEXT:    lw a1, 12(sp)
354; RV32FD-NEXT:    addi sp, sp, 16
355; RV32FD-NEXT:    ret
356;
357; RV64F-LABEL: bitcast_double_or:
358; RV64F:       # %bb.0:
359; RV64F-NEXT:    addi sp, sp, -16
360; RV64F-NEXT:    sd ra, 8(sp)
361; RV64F-NEXT:    sd s0, 0(sp)
362; RV64F-NEXT:    mv s0, a0
363; RV64F-NEXT:    call __muldf3
364; RV64F-NEXT:    addi a1, zero, -1
365; RV64F-NEXT:    slli a1, a1, 63
366; RV64F-NEXT:    or a1, a0, a1
367; RV64F-NEXT:    mv a0, s0
368; RV64F-NEXT:    call __muldf3
369; RV64F-NEXT:    ld s0, 0(sp)
370; RV64F-NEXT:    ld ra, 8(sp)
371; RV64F-NEXT:    addi sp, sp, 16
372; RV64F-NEXT:    ret
373;
374; RV64FD-LABEL: bitcast_double_or:
375; RV64FD:       # %bb.0:
376; RV64FD-NEXT:    fmv.d.x ft0, a1
377; RV64FD-NEXT:    fmv.d.x ft1, a0
378; RV64FD-NEXT:    fmul.d ft0, ft1, ft0
379; RV64FD-NEXT:    fabs.d ft0, ft0
380; RV64FD-NEXT:    fneg.d ft0, ft0
381; RV64FD-NEXT:    fmul.d ft0, ft1, ft0
382; RV64FD-NEXT:    fmv.x.d a0, ft0
383; RV64FD-NEXT:    ret
384  %a3 = fmul double %a1, %a2
385  %bc1 = bitcast double %a3 to i64
386  %and = or i64 %bc1, 9223372036854775808
387  %bc2 = bitcast i64 %and to double
388  %a4 = fmul double %a1, %bc2
389  ret double %a4
390}
391