Skip to content

Commit b64e7e0

Browse files
committed
[SimplifyCFG] Add tests for hoisting of commutative instructions (NFC)
1 parent a449b85 commit b64e7e0

File tree

1 file changed

+347
-0
lines changed

1 file changed

+347
-0
lines changed

llvm/test/Transforms/SimplifyCFG/hoist-common-code.ll

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,350 @@ exit: ; preds = %bb2, %bb1, %bb0
154154
%result = phi i1 [ %0, %bb0 ], [ %1, %bb1 ], [ %2, %bb2 ]
155155
ret i1 %result
156156
}
157+
158+
declare void @foo()
159+
160+
define i1 @test_icmp_simple(i1 %c, i32 %a, i32 %b) {
161+
; CHECK-LABEL: @test_icmp_simple(
162+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
163+
; CHECK: common.ret:
164+
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i1 [ [[CMP1:%.*]], [[IF]] ], [ [[CMP2:%.*]], [[ELSE]] ]
165+
; CHECK-NEXT: ret i1 [[COMMON_RET_OP]]
166+
; CHECK: if:
167+
; CHECK-NEXT: [[CMP1]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
168+
; CHECK-NEXT: call void @foo()
169+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
170+
; CHECK: else:
171+
; CHECK-NEXT: [[CMP2]] = icmp ugt i32 [[B]], [[A]]
172+
; CHECK-NEXT: call void @bar()
173+
; CHECK-NEXT: br label [[COMMON_RET]]
174+
;
175+
br i1 %c, label %if, label %else
176+
177+
if:
178+
%cmp1 = icmp ult i32 %a, %b
179+
call void @foo()
180+
ret i1 %cmp1
181+
182+
else:
183+
%cmp2 = icmp ugt i32 %b, %a
184+
call void @bar()
185+
ret i1 %cmp2
186+
}
187+
188+
define void @test_icmp_complex(i1 %c, i32 %a, i32 %b) {
189+
; CHECK-LABEL: @test_icmp_complex(
190+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
191+
; CHECK: if:
192+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
193+
; CHECK-NEXT: br i1 [[CMP1]], label [[IF2:%.*]], label [[ELSE2:%.*]]
194+
; CHECK: else:
195+
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i32 [[B]], [[A]]
196+
; CHECK-NEXT: br i1 [[CMP2]], label [[IF2]], label [[ELSE2]]
197+
; CHECK: common.ret:
198+
; CHECK-NEXT: ret void
199+
; CHECK: if2:
200+
; CHECK-NEXT: call void @foo()
201+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
202+
; CHECK: else2:
203+
; CHECK-NEXT: call void @bar()
204+
; CHECK-NEXT: br label [[COMMON_RET]]
205+
;
206+
br i1 %c, label %if, label %else
207+
208+
if:
209+
%cmp1 = icmp ult i32 %a, %b
210+
br i1 %cmp1, label %if2, label %else2
211+
212+
else:
213+
%cmp2 = icmp ugt i32 %b, %a
214+
br i1 %cmp2, label %if2, label %else2
215+
216+
if2:
217+
call void @foo()
218+
ret void
219+
220+
else2:
221+
call void @bar()
222+
ret void
223+
}
224+
225+
define i1 @test_icmp_wrong_operands(i1 %c, i32 %a, i32 %b) {
226+
; CHECK-LABEL: @test_icmp_wrong_operands(
227+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
228+
; CHECK: common.ret:
229+
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i1 [ [[CMP1:%.*]], [[IF]] ], [ [[CMP2:%.*]], [[ELSE]] ]
230+
; CHECK-NEXT: ret i1 [[COMMON_RET_OP]]
231+
; CHECK: if:
232+
; CHECK-NEXT: [[CMP1]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
233+
; CHECK-NEXT: call void @foo()
234+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
235+
; CHECK: else:
236+
; CHECK-NEXT: [[CMP2]] = icmp ugt i32 [[A]], [[B]]
237+
; CHECK-NEXT: call void @bar()
238+
; CHECK-NEXT: br label [[COMMON_RET]]
239+
;
240+
br i1 %c, label %if, label %else
241+
242+
if:
243+
%cmp1 = icmp ult i32 %a, %b
244+
call void @foo()
245+
ret i1 %cmp1
246+
247+
else:
248+
%cmp2 = icmp ugt i32 %a, %b
249+
call void @bar()
250+
ret i1 %cmp2
251+
}
252+
253+
define i1 @test_icmp_wrong_pred(i1 %c, i32 %a, i32 %b) {
254+
; CHECK-LABEL: @test_icmp_wrong_pred(
255+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
256+
; CHECK: common.ret:
257+
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i1 [ [[CMP1:%.*]], [[IF]] ], [ [[CMP2:%.*]], [[ELSE]] ]
258+
; CHECK-NEXT: ret i1 [[COMMON_RET_OP]]
259+
; CHECK: if:
260+
; CHECK-NEXT: [[CMP1]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
261+
; CHECK-NEXT: call void @foo()
262+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
263+
; CHECK: else:
264+
; CHECK-NEXT: [[CMP2]] = icmp uge i32 [[B]], [[A]]
265+
; CHECK-NEXT: call void @bar()
266+
; CHECK-NEXT: br label [[COMMON_RET]]
267+
;
268+
br i1 %c, label %if, label %else
269+
270+
if:
271+
%cmp1 = icmp ult i32 %a, %b
272+
call void @foo()
273+
ret i1 %cmp1
274+
275+
else:
276+
%cmp2 = icmp uge i32 %b, %a
277+
call void @bar()
278+
ret i1 %cmp2
279+
}
280+
281+
define i32 @test_binop(i1 %c, i32 %a, i32 %b) {
282+
; CHECK-LABEL: @test_binop(
283+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
284+
; CHECK: common.ret:
285+
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
286+
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
287+
; CHECK: if:
288+
; CHECK-NEXT: [[OP1]] = add i32 [[A:%.*]], [[B:%.*]]
289+
; CHECK-NEXT: call void @foo()
290+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
291+
; CHECK: else:
292+
; CHECK-NEXT: [[OP2]] = add i32 [[B]], [[A]]
293+
; CHECK-NEXT: call void @bar()
294+
; CHECK-NEXT: br label [[COMMON_RET]]
295+
;
296+
br i1 %c, label %if, label %else
297+
298+
if:
299+
%op1 = add i32 %a, %b
300+
call void @foo()
301+
ret i32 %op1
302+
303+
else:
304+
%op2 = add i32 %b, %a
305+
call void @bar()
306+
ret i32 %op2
307+
}
308+
309+
define i32 @test_binop_flags(i1 %c, i32 %a, i32 %b) {
310+
; CHECK-LABEL: @test_binop_flags(
311+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
312+
; CHECK: common.ret:
313+
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
314+
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
315+
; CHECK: if:
316+
; CHECK-NEXT: [[OP1]] = add nuw nsw i32 [[A:%.*]], [[B:%.*]]
317+
; CHECK-NEXT: call void @foo()
318+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
319+
; CHECK: else:
320+
; CHECK-NEXT: [[OP2]] = add nsw i32 [[B]], [[A]]
321+
; CHECK-NEXT: call void @bar()
322+
; CHECK-NEXT: br label [[COMMON_RET]]
323+
;
324+
br i1 %c, label %if, label %else
325+
326+
if:
327+
%op1 = add nuw nsw i32 %a, %b
328+
call void @foo()
329+
ret i32 %op1
330+
331+
else:
332+
%op2 = add nsw i32 %b, %a
333+
call void @bar()
334+
ret i32 %op2
335+
}
336+
337+
define i32 @test_binop_not_commutative(i1 %c, i32 %a, i32 %b) {
338+
; CHECK-LABEL: @test_binop_not_commutative(
339+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
340+
; CHECK: common.ret:
341+
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
342+
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
343+
; CHECK: if:
344+
; CHECK-NEXT: [[OP1]] = sub i32 [[A:%.*]], [[B:%.*]]
345+
; CHECK-NEXT: call void @foo()
346+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
347+
; CHECK: else:
348+
; CHECK-NEXT: [[OP2]] = sub i32 [[B]], [[A]]
349+
; CHECK-NEXT: call void @bar()
350+
; CHECK-NEXT: br label [[COMMON_RET]]
351+
;
352+
br i1 %c, label %if, label %else
353+
354+
if:
355+
%op1 = sub i32 %a, %b
356+
call void @foo()
357+
ret i32 %op1
358+
359+
else:
360+
%op2 = sub i32 %b, %a
361+
call void @bar()
362+
ret i32 %op2
363+
}
364+
365+
define i32 @test_binop_wrong_ops(i1 %c, i32 %a, i32 %b, i32 %d) {
366+
; CHECK-LABEL: @test_binop_wrong_ops(
367+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
368+
; CHECK: common.ret:
369+
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
370+
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
371+
; CHECK: if:
372+
; CHECK-NEXT: [[OP1]] = add i32 [[A:%.*]], [[B:%.*]]
373+
; CHECK-NEXT: call void @foo()
374+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
375+
; CHECK: else:
376+
; CHECK-NEXT: [[OP2]] = add i32 [[B]], [[D:%.*]]
377+
; CHECK-NEXT: call void @bar()
378+
; CHECK-NEXT: br label [[COMMON_RET]]
379+
;
380+
br i1 %c, label %if, label %else
381+
382+
if:
383+
%op1 = add i32 %a, %b
384+
call void @foo()
385+
ret i32 %op1
386+
387+
else:
388+
%op2 = add i32 %b, %d
389+
call void @bar()
390+
ret i32 %op2
391+
}
392+
393+
define i32 @test_intrin(i1 %c, i32 %a, i32 %b) {
394+
; CHECK-LABEL: @test_intrin(
395+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
396+
; CHECK: common.ret:
397+
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
398+
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
399+
; CHECK: if:
400+
; CHECK-NEXT: [[OP1]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 [[B:%.*]])
401+
; CHECK-NEXT: call void @foo()
402+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
403+
; CHECK: else:
404+
; CHECK-NEXT: [[OP2]] = call i32 @llvm.umin.i32(i32 [[B]], i32 [[A]])
405+
; CHECK-NEXT: call void @bar()
406+
; CHECK-NEXT: br label [[COMMON_RET]]
407+
;
408+
br i1 %c, label %if, label %else
409+
410+
if:
411+
%op1 = call i32 @llvm.umin(i32 %a, i32 %b)
412+
call void @foo()
413+
ret i32 %op1
414+
415+
else:
416+
%op2 = call i32 @llvm.umin(i32 %b, i32 %a)
417+
call void @bar()
418+
ret i32 %op2
419+
}
420+
421+
define i32 @test_intrin_not_same(i1 %c, i32 %a, i32 %b) {
422+
; CHECK-LABEL: @test_intrin_not_same(
423+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
424+
; CHECK: common.ret:
425+
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
426+
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
427+
; CHECK: if:
428+
; CHECK-NEXT: [[OP1]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 [[B:%.*]])
429+
; CHECK-NEXT: call void @foo()
430+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
431+
; CHECK: else:
432+
; CHECK-NEXT: [[OP2]] = call i32 @llvm.umax.i32(i32 [[B]], i32 [[A]])
433+
; CHECK-NEXT: call void @bar()
434+
; CHECK-NEXT: br label [[COMMON_RET]]
435+
;
436+
br i1 %c, label %if, label %else
437+
438+
if:
439+
%op1 = call i32 @llvm.umin(i32 %a, i32 %b)
440+
call void @foo()
441+
ret i32 %op1
442+
443+
else:
444+
%op2 = call i32 @llvm.umax(i32 %b, i32 %a)
445+
call void @bar()
446+
ret i32 %op2
447+
}
448+
449+
define float @test_intrin_3arg(i1 %c, float %a, float %b, float %d) {
450+
; CHECK-LABEL: @test_intrin_3arg(
451+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
452+
; CHECK: common.ret:
453+
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi float [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
454+
; CHECK-NEXT: ret float [[COMMON_RET_OP]]
455+
; CHECK: if:
456+
; CHECK-NEXT: [[OP1]] = call float @llvm.fma.f32(float [[A:%.*]], float [[B:%.*]], float [[D:%.*]])
457+
; CHECK-NEXT: call void @foo()
458+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
459+
; CHECK: else:
460+
; CHECK-NEXT: [[OP2]] = call float @llvm.fma.f32(float [[B]], float [[A]], float [[D]])
461+
; CHECK-NEXT: call void @bar()
462+
; CHECK-NEXT: br label [[COMMON_RET]]
463+
;
464+
br i1 %c, label %if, label %else
465+
466+
if:
467+
%op1 = call float @llvm.fma(float %a, float %b, float %d)
468+
call void @foo()
469+
ret float %op1
470+
471+
else:
472+
%op2 = call float @llvm.fma(float %b, float %a, float %d)
473+
call void @bar()
474+
ret float %op2
475+
}
476+
477+
define float @test_intrin_3arg_wrong_args_commuted(i1 %c, float %a, float %b, float %d) {
478+
; CHECK-LABEL: @test_intrin_3arg_wrong_args_commuted(
479+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
480+
; CHECK: common.ret:
481+
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi float [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
482+
; CHECK-NEXT: ret float [[COMMON_RET_OP]]
483+
; CHECK: if:
484+
; CHECK-NEXT: [[OP1]] = call float @llvm.fma.f32(float [[A:%.*]], float [[B:%.*]], float [[D:%.*]])
485+
; CHECK-NEXT: call void @foo()
486+
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
487+
; CHECK: else:
488+
; CHECK-NEXT: [[OP2]] = call float @llvm.fma.f32(float [[A]], float [[D]], float [[B]])
489+
; CHECK-NEXT: call void @bar()
490+
; CHECK-NEXT: br label [[COMMON_RET]]
491+
;
492+
br i1 %c, label %if, label %else
493+
494+
if:
495+
%op1 = call float @llvm.fma(float %a, float %b, float %d)
496+
call void @foo()
497+
ret float %op1
498+
499+
else:
500+
%op2 = call float @llvm.fma(float %a, float %d, float %b)
501+
call void @bar()
502+
ret float %op2
503+
}

0 commit comments

Comments
 (0)