xref: /llvm-project/llvm/test/CodeGen/RISCV/cmov-branch-opt.ll (revision 9122c5235ec85ce0c0ad337e862b006e7b349d84)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=riscv64 -mattr=+c -verify-machineinstrs < %s \
3; RUN:   | FileCheck -check-prefix=NOCMOV %s
4; RUN: llc -mtriple=riscv64 -mattr=+conditional-cmv-fusion,+c -verify-machineinstrs < %s \
5; RUN:   | FileCheck -check-prefixes=CMOV,CMOV-NOZICOND %s
6; RUN: llc -mtriple=riscv64 -mattr=+conditional-cmv-fusion,+c,+zicond -verify-machineinstrs < %s \
7; RUN:   | FileCheck -check-prefixes=CMOV,CMOV-ZICOND %s
8; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt -verify-machineinstrs < %s \
9; RUN:   | FileCheck -check-prefixes=SHORT_FORWARD,SFB-NOZICOND %s
10; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt,+c -verify-machineinstrs < %s \
11; RUN:   | FileCheck -check-prefixes=SHORT_FORWARD,SFB-NOZICOND %s
12; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt,+zicond -verify-machineinstrs < %s \
13; RUN:   | FileCheck -check-prefixes=SHORT_FORWARD,SFB-ZICOND %s
14
15; The conditional move optimization in sifive-p450 requires that only a
16; single c.mv instruction appears in the branch shadow.
17
18; The sifive-7-series can predicate an xor.
19
20define signext i32 @test1(i32 signext %x, i32 signext %y, i32 signext %z) {
21; NOCMOV-LABEL: test1:
22; NOCMOV:       # %bb.0:
23; NOCMOV-NEXT:    snez a2, a2
24; NOCMOV-NEXT:    addi a2, a2, -1
25; NOCMOV-NEXT:    and a1, a1, a2
26; NOCMOV-NEXT:    xor a0, a0, a1
27; NOCMOV-NEXT:    ret
28;
29; CMOV-LABEL: test1:
30; CMOV:       # %bb.0:
31; CMOV-NEXT:    xor a1, a1, a0
32; CMOV-NEXT:    bnez a2, .LBB0_2
33; CMOV-NEXT:  # %bb.1:
34; CMOV-NEXT:    mv a0, a1
35; CMOV-NEXT:  .LBB0_2:
36; CMOV-NEXT:    ret
37;
38; SHORT_FORWARD-LABEL: test1:
39; SHORT_FORWARD:       # %bb.0:
40; SHORT_FORWARD-NEXT:    bnez a2, .LBB0_2
41; SHORT_FORWARD-NEXT:  # %bb.1:
42; SHORT_FORWARD-NEXT:    xor a0, a0, a1
43; SHORT_FORWARD-NEXT:  .LBB0_2:
44; SHORT_FORWARD-NEXT:    ret
45  %c = icmp eq i32 %z, 0
46  %a = xor i32 %x, %y
47  %b = select i1 %c, i32 %a, i32 %x
48  ret i32 %b
49}
50
51define signext i32 @test2(i32 signext %x, i32 signext %y, i32 signext %z) {
52; NOCMOV-LABEL: test2:
53; NOCMOV:       # %bb.0:
54; NOCMOV-NEXT:    seqz a2, a2
55; NOCMOV-NEXT:    addi a2, a2, -1
56; NOCMOV-NEXT:    and a1, a1, a2
57; NOCMOV-NEXT:    xor a0, a0, a1
58; NOCMOV-NEXT:    ret
59;
60; CMOV-LABEL: test2:
61; CMOV:       # %bb.0:
62; CMOV-NEXT:    xor a1, a1, a0
63; CMOV-NEXT:    beqz a2, .LBB1_2
64; CMOV-NEXT:  # %bb.1:
65; CMOV-NEXT:    mv a0, a1
66; CMOV-NEXT:  .LBB1_2:
67; CMOV-NEXT:    ret
68;
69; SHORT_FORWARD-LABEL: test2:
70; SHORT_FORWARD:       # %bb.0:
71; SHORT_FORWARD-NEXT:    beqz a2, .LBB1_2
72; SHORT_FORWARD-NEXT:  # %bb.1:
73; SHORT_FORWARD-NEXT:    xor a0, a0, a1
74; SHORT_FORWARD-NEXT:  .LBB1_2:
75; SHORT_FORWARD-NEXT:    ret
76  %c = icmp eq i32 %z, 0
77  %a = xor i32 %x, %y
78  %b = select i1 %c, i32 %x, i32 %a
79  ret i32 %b
80}
81
82; Make sure we don't share the same basic block for two selects with the same
83; condition.
84define signext i32 @test3(i32 signext %v, i32 signext %w, i32 signext %x, i32 signext %y, i32 signext %z) {
85; NOCMOV-LABEL: test3:
86; NOCMOV:       # %bb.0:
87; NOCMOV-NEXT:    seqz a4, a4
88; NOCMOV-NEXT:    addi a4, a4, -1
89; NOCMOV-NEXT:    and a1, a1, a4
90; NOCMOV-NEXT:    and a3, a3, a4
91; NOCMOV-NEXT:    xor a0, a0, a1
92; NOCMOV-NEXT:    xor a2, a2, a3
93; NOCMOV-NEXT:    addw a0, a0, a2
94; NOCMOV-NEXT:    ret
95;
96; CMOV-LABEL: test3:
97; CMOV:       # %bb.0:
98; CMOV-NEXT:    xor a1, a1, a0
99; CMOV-NEXT:    xor a3, a3, a2
100; CMOV-NEXT:    bnez a4, .LBB2_2
101; CMOV-NEXT:  # %bb.1:
102; CMOV-NEXT:    mv a1, a0
103; CMOV-NEXT:  .LBB2_2:
104; CMOV-NEXT:    bnez a4, .LBB2_4
105; CMOV-NEXT:  # %bb.3:
106; CMOV-NEXT:    mv a3, a2
107; CMOV-NEXT:  .LBB2_4:
108; CMOV-NEXT:    addw a0, a1, a3
109; CMOV-NEXT:    ret
110;
111; SHORT_FORWARD-LABEL: test3:
112; SHORT_FORWARD:       # %bb.0:
113; SHORT_FORWARD-NEXT:    beqz a4, .LBB2_2
114; SHORT_FORWARD-NEXT:  # %bb.1:
115; SHORT_FORWARD-NEXT:    xor a0, a0, a1
116; SHORT_FORWARD-NEXT:  .LBB2_2:
117; SHORT_FORWARD-NEXT:    beqz a4, .LBB2_4
118; SHORT_FORWARD-NEXT:  # %bb.3:
119; SHORT_FORWARD-NEXT:    xor a2, a2, a3
120; SHORT_FORWARD-NEXT:  .LBB2_4:
121; SHORT_FORWARD-NEXT:    addw a0, a0, a2
122; SHORT_FORWARD-NEXT:    ret
123  %c = icmp eq i32 %z, 0
124  %a = xor i32 %v, %w
125  %b = select i1 %c, i32 %v, i32 %a
126  %d = xor i32 %x, %y
127  %e = select i1 %c, i32 %x, i32 %d
128  %f = add i32 %b, %e
129  ret i32 %f
130}
131
132define signext i32 @test4(i32 signext %x, i32 signext %y, i32 signext %z) {
133; NOCMOV-LABEL: test4:
134; NOCMOV:       # %bb.0:
135; NOCMOV-NEXT:    snez a0, a2
136; NOCMOV-NEXT:    addi a0, a0, -1
137; NOCMOV-NEXT:    andi a0, a0, 3
138; NOCMOV-NEXT:    ret
139;
140; CMOV-NOZICOND-LABEL: test4:
141; CMOV-NOZICOND:       # %bb.0:
142; CMOV-NOZICOND-NEXT:    li a1, 0
143; CMOV-NOZICOND-NEXT:    li a0, 3
144; CMOV-NOZICOND-NEXT:    beqz a2, .LBB3_2
145; CMOV-NOZICOND-NEXT:  # %bb.1:
146; CMOV-NOZICOND-NEXT:    mv a0, a1
147; CMOV-NOZICOND-NEXT:  .LBB3_2:
148; CMOV-NOZICOND-NEXT:    ret
149;
150; CMOV-ZICOND-LABEL: test4:
151; CMOV-ZICOND:       # %bb.0:
152; CMOV-ZICOND-NEXT:    li a0, 3
153; CMOV-ZICOND-NEXT:    czero.nez a0, a0, a2
154; CMOV-ZICOND-NEXT:    ret
155;
156; SFB-NOZICOND-LABEL: test4:
157; SFB-NOZICOND:       # %bb.0:
158; SFB-NOZICOND-NEXT:    li a0, 3
159; SFB-NOZICOND-NEXT:    beqz a2, .LBB3_2
160; SFB-NOZICOND-NEXT:  # %bb.1:
161; SFB-NOZICOND-NEXT:    li a0, 0
162; SFB-NOZICOND-NEXT:  .LBB3_2:
163; SFB-NOZICOND-NEXT:    ret
164;
165; SFB-ZICOND-LABEL: test4:
166; SFB-ZICOND:       # %bb.0:
167; SFB-ZICOND-NEXT:    li a0, 3
168; SFB-ZICOND-NEXT:    czero.nez a0, a0, a2
169; SFB-ZICOND-NEXT:    ret
170  %c = icmp eq i32 %z, 0
171  %a = select i1 %c, i32 3, i32 0
172  ret i32 %a
173}
174
175define i16 @select_xor_1(i16 %A, i8 %cond) {
176; NOCMOV-LABEL: select_xor_1:
177; NOCMOV:       # %bb.0: # %entry
178; NOCMOV-NEXT:    slli a1, a1, 63
179; NOCMOV-NEXT:    srai a1, a1, 63
180; NOCMOV-NEXT:    andi a1, a1, 43
181; NOCMOV-NEXT:    xor a0, a0, a1
182; NOCMOV-NEXT:    ret
183;
184; CMOV-LABEL: select_xor_1:
185; CMOV:       # %bb.0: # %entry
186; CMOV-NEXT:    andi a1, a1, 1
187; CMOV-NEXT:    xori a2, a0, 43
188; CMOV-NEXT:    beqz a1, .LBB4_2
189; CMOV-NEXT:  # %bb.1: # %entry
190; CMOV-NEXT:    mv a0, a2
191; CMOV-NEXT:  .LBB4_2: # %entry
192; CMOV-NEXT:    ret
193;
194; SHORT_FORWARD-LABEL: select_xor_1:
195; SHORT_FORWARD:       # %bb.0: # %entry
196; SHORT_FORWARD-NEXT:    andi a1, a1, 1
197; SHORT_FORWARD-NEXT:    beqz a1, .LBB4_2
198; SHORT_FORWARD-NEXT:  # %bb.1: # %entry
199; SHORT_FORWARD-NEXT:    xori a0, a0, 43
200; SHORT_FORWARD-NEXT:  .LBB4_2: # %entry
201; SHORT_FORWARD-NEXT:    ret
202entry:
203 %and = and i8 %cond, 1
204 %cmp10 = icmp eq i8 %and, 0
205 %0 = xor i16 %A, 43
206 %1 = select i1 %cmp10, i16 %A, i16 %0
207 ret i16 %1
208}
209
210; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
211; icmp eq (and %cond, 1), 0
212define i16 @select_xor_1b(i16 %A, i8 %cond) {
213; NOCMOV-LABEL: select_xor_1b:
214; NOCMOV:       # %bb.0: # %entry
215; NOCMOV-NEXT:    slli a1, a1, 63
216; NOCMOV-NEXT:    srai a1, a1, 63
217; NOCMOV-NEXT:    andi a1, a1, 43
218; NOCMOV-NEXT:    xor a0, a0, a1
219; NOCMOV-NEXT:    ret
220;
221; CMOV-LABEL: select_xor_1b:
222; CMOV:       # %bb.0: # %entry
223; CMOV-NEXT:    andi a1, a1, 1
224; CMOV-NEXT:    xori a2, a0, 43
225; CMOV-NEXT:    beqz a1, .LBB5_2
226; CMOV-NEXT:  # %bb.1: # %entry
227; CMOV-NEXT:    mv a0, a2
228; CMOV-NEXT:  .LBB5_2: # %entry
229; CMOV-NEXT:    ret
230;
231; SHORT_FORWARD-LABEL: select_xor_1b:
232; SHORT_FORWARD:       # %bb.0: # %entry
233; SHORT_FORWARD-NEXT:    andi a1, a1, 1
234; SHORT_FORWARD-NEXT:    beqz a1, .LBB5_2
235; SHORT_FORWARD-NEXT:  # %bb.1: # %entry
236; SHORT_FORWARD-NEXT:    xori a0, a0, 43
237; SHORT_FORWARD-NEXT:  .LBB5_2: # %entry
238; SHORT_FORWARD-NEXT:    ret
239entry:
240 %and = and i8 %cond, 1
241 %cmp10 = icmp ne i8 %and, 1
242 %0 = xor i16 %A, 43
243 %1 = select i1 %cmp10, i16 %A, i16 %0
244 ret i16 %1
245}
246
247define i32 @select_xor_2(i32 %A, i32 %B, i8 %cond) {
248; NOCMOV-LABEL: select_xor_2:
249; NOCMOV:       # %bb.0: # %entry
250; NOCMOV-NEXT:    slli a2, a2, 63
251; NOCMOV-NEXT:    srai a2, a2, 63
252; NOCMOV-NEXT:    and a1, a1, a2
253; NOCMOV-NEXT:    xor a0, a0, a1
254; NOCMOV-NEXT:    ret
255;
256; CMOV-LABEL: select_xor_2:
257; CMOV:       # %bb.0: # %entry
258; CMOV-NEXT:    andi a2, a2, 1
259; CMOV-NEXT:    xor a1, a1, a0
260; CMOV-NEXT:    beqz a2, .LBB6_2
261; CMOV-NEXT:  # %bb.1: # %entry
262; CMOV-NEXT:    mv a0, a1
263; CMOV-NEXT:  .LBB6_2: # %entry
264; CMOV-NEXT:    ret
265;
266; SFB-ZICOND-LABEL: select_xor_2:
267; SFB-ZICOND:       # %bb.0: # %entry
268; SFB-ZICOND-NEXT:    andi a2, a2, 1
269; SFB-ZICOND-NEXT:    beqz a2, .LBB6_2
270; SFB-ZICOND-NEXT:  # %bb.1: # %entry
271; SFB-ZICOND-NEXT:    xor a0, a1, a0
272; SFB-ZICOND-NEXT:  .LBB6_2: # %entry
273; SFB-ZICOND-NEXT:    ret
274entry:
275 %and = and i8 %cond, 1
276 %cmp10 = icmp eq i8 %and, 0
277 %0 = xor i32 %B, %A
278 %1 = select i1 %cmp10, i32 %A, i32 %0
279 ret i32 %1
280}
281
282; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
283; icmp eq (and %cond, 1), 0
284define i32 @select_xor_2b(i32 %A, i32 %B, i8 %cond) {
285; NOCMOV-LABEL: select_xor_2b:
286; NOCMOV:       # %bb.0: # %entry
287; NOCMOV-NEXT:    slli a2, a2, 63
288; NOCMOV-NEXT:    srai a2, a2, 63
289; NOCMOV-NEXT:    and a1, a1, a2
290; NOCMOV-NEXT:    xor a0, a0, a1
291; NOCMOV-NEXT:    ret
292;
293; CMOV-LABEL: select_xor_2b:
294; CMOV:       # %bb.0: # %entry
295; CMOV-NEXT:    andi a2, a2, 1
296; CMOV-NEXT:    xor a1, a1, a0
297; CMOV-NEXT:    beqz a2, .LBB7_2
298; CMOV-NEXT:  # %bb.1: # %entry
299; CMOV-NEXT:    mv a0, a1
300; CMOV-NEXT:  .LBB7_2: # %entry
301; CMOV-NEXT:    ret
302;
303; SFB-ZICOND-LABEL: select_xor_2b:
304; SFB-ZICOND:       # %bb.0: # %entry
305; SFB-ZICOND-NEXT:    andi a2, a2, 1
306; SFB-ZICOND-NEXT:    beqz a2, .LBB7_2
307; SFB-ZICOND-NEXT:  # %bb.1: # %entry
308; SFB-ZICOND-NEXT:    xor a0, a1, a0
309; SFB-ZICOND-NEXT:  .LBB7_2: # %entry
310; SFB-ZICOND-NEXT:    ret
311entry:
312 %and = and i8 %cond, 1
313 %cmp10 = icmp ne i8 %and, 1
314 %0 = xor i32 %B, %A
315 %1 = select i1 %cmp10, i32 %A, i32 %0
316 ret i32 %1
317}
318
319define i32 @select_or(i32 %A, i32 %B, i8 %cond) {
320; NOCMOV-LABEL: select_or:
321; NOCMOV:       # %bb.0: # %entry
322; NOCMOV-NEXT:    slli a2, a2, 63
323; NOCMOV-NEXT:    srai a2, a2, 63
324; NOCMOV-NEXT:    and a1, a1, a2
325; NOCMOV-NEXT:    or a0, a0, a1
326; NOCMOV-NEXT:    ret
327;
328; CMOV-LABEL: select_or:
329; CMOV:       # %bb.0: # %entry
330; CMOV-NEXT:    andi a2, a2, 1
331; CMOV-NEXT:    or a1, a1, a0
332; CMOV-NEXT:    beqz a2, .LBB8_2
333; CMOV-NEXT:  # %bb.1: # %entry
334; CMOV-NEXT:    mv a0, a1
335; CMOV-NEXT:  .LBB8_2: # %entry
336; CMOV-NEXT:    ret
337;
338; SFB-ZICOND-LABEL: select_or:
339; SFB-ZICOND:       # %bb.0: # %entry
340; SFB-ZICOND-NEXT:    andi a2, a2, 1
341; SFB-ZICOND-NEXT:    beqz a2, .LBB8_2
342; SFB-ZICOND-NEXT:  # %bb.1: # %entry
343; SFB-ZICOND-NEXT:    or a0, a1, a0
344; SFB-ZICOND-NEXT:  .LBB8_2: # %entry
345; SFB-ZICOND-NEXT:    ret
346entry:
347 %and = and i8 %cond, 1
348 %cmp10 = icmp eq i8 %and, 0
349 %0 = or i32 %B, %A
350 %1 = select i1 %cmp10, i32 %A, i32 %0
351 ret i32 %1
352}
353
354; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
355; icmp eq (and %cond, 1), 0
356define i32 @select_or_b(i32 %A, i32 %B, i8 %cond) {
357; NOCMOV-LABEL: select_or_b:
358; NOCMOV:       # %bb.0: # %entry
359; NOCMOV-NEXT:    slli a2, a2, 63
360; NOCMOV-NEXT:    srai a2, a2, 63
361; NOCMOV-NEXT:    and a1, a1, a2
362; NOCMOV-NEXT:    or a0, a0, a1
363; NOCMOV-NEXT:    ret
364;
365; CMOV-LABEL: select_or_b:
366; CMOV:       # %bb.0: # %entry
367; CMOV-NEXT:    andi a2, a2, 1
368; CMOV-NEXT:    or a1, a1, a0
369; CMOV-NEXT:    beqz a2, .LBB9_2
370; CMOV-NEXT:  # %bb.1: # %entry
371; CMOV-NEXT:    mv a0, a1
372; CMOV-NEXT:  .LBB9_2: # %entry
373; CMOV-NEXT:    ret
374;
375; SFB-ZICOND-LABEL: select_or_b:
376; SFB-ZICOND:       # %bb.0: # %entry
377; SFB-ZICOND-NEXT:    andi a2, a2, 1
378; SFB-ZICOND-NEXT:    beqz a2, .LBB9_2
379; SFB-ZICOND-NEXT:  # %bb.1: # %entry
380; SFB-ZICOND-NEXT:    or a0, a1, a0
381; SFB-ZICOND-NEXT:  .LBB9_2: # %entry
382; SFB-ZICOND-NEXT:    ret
383entry:
384 %and = and i8 %cond, 1
385 %cmp10 = icmp ne i8 %and, 1
386 %0 = or i32 %B, %A
387 %1 = select i1 %cmp10, i32 %A, i32 %0
388 ret i32 %1
389}
390
391define i32 @select_or_1(i32 %A, i32 %B, i32 %cond) {
392; NOCMOV-LABEL: select_or_1:
393; NOCMOV:       # %bb.0: # %entry
394; NOCMOV-NEXT:    slli a2, a2, 63
395; NOCMOV-NEXT:    srai a2, a2, 63
396; NOCMOV-NEXT:    and a1, a1, a2
397; NOCMOV-NEXT:    or a0, a0, a1
398; NOCMOV-NEXT:    ret
399;
400; CMOV-LABEL: select_or_1:
401; CMOV:       # %bb.0: # %entry
402; CMOV-NEXT:    andi a2, a2, 1
403; CMOV-NEXT:    or a1, a1, a0
404; CMOV-NEXT:    beqz a2, .LBB10_2
405; CMOV-NEXT:  # %bb.1: # %entry
406; CMOV-NEXT:    mv a0, a1
407; CMOV-NEXT:  .LBB10_2: # %entry
408; CMOV-NEXT:    ret
409;
410; SFB-ZICOND-LABEL: select_or_1:
411; SFB-ZICOND:       # %bb.0: # %entry
412; SFB-ZICOND-NEXT:    andi a2, a2, 1
413; SFB-ZICOND-NEXT:    beqz a2, .LBB10_2
414; SFB-ZICOND-NEXT:  # %bb.1: # %entry
415; SFB-ZICOND-NEXT:    or a0, a1, a0
416; SFB-ZICOND-NEXT:  .LBB10_2: # %entry
417; SFB-ZICOND-NEXT:    ret
418entry:
419 %and = and i32 %cond, 1
420 %cmp10 = icmp eq i32 %and, 0
421 %0 = or i32 %B, %A
422 %1 = select i1 %cmp10, i32 %A, i32 %0
423 ret i32 %1
424}
425
426; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
427; icmp eq (and %cond, 1), 0
428define i32 @select_or_1b(i32 %A, i32 %B, i32 %cond) {
429; NOCMOV-LABEL: select_or_1b:
430; NOCMOV:       # %bb.0: # %entry
431; NOCMOV-NEXT:    slli a2, a2, 63
432; NOCMOV-NEXT:    srai a2, a2, 63
433; NOCMOV-NEXT:    and a1, a1, a2
434; NOCMOV-NEXT:    or a0, a0, a1
435; NOCMOV-NEXT:    ret
436;
437; CMOV-LABEL: select_or_1b:
438; CMOV:       # %bb.0: # %entry
439; CMOV-NEXT:    andi a2, a2, 1
440; CMOV-NEXT:    or a1, a1, a0
441; CMOV-NEXT:    beqz a2, .LBB11_2
442; CMOV-NEXT:  # %bb.1: # %entry
443; CMOV-NEXT:    mv a0, a1
444; CMOV-NEXT:  .LBB11_2: # %entry
445; CMOV-NEXT:    ret
446;
447; SFB-ZICOND-LABEL: select_or_1b:
448; SFB-ZICOND:       # %bb.0: # %entry
449; SFB-ZICOND-NEXT:    andi a2, a2, 1
450; SFB-ZICOND-NEXT:    beqz a2, .LBB11_2
451; SFB-ZICOND-NEXT:  # %bb.1: # %entry
452; SFB-ZICOND-NEXT:    or a0, a1, a0
453; SFB-ZICOND-NEXT:  .LBB11_2: # %entry
454; SFB-ZICOND-NEXT:    ret
455entry:
456 %and = and i32 %cond, 1
457 %cmp10 = icmp ne i32 %and, 1
458 %0 = or i32 %B, %A
459 %1 = select i1 %cmp10, i32 %A, i32 %0
460 ret i32 %1
461}
462