Skip to content

Commit d362aab

Browse files
committed
InstCombine: Add baseline tests for ldexp reassociation combine
1 parent db58a9c commit d362aab

File tree

1 file changed

+275
-0
lines changed
  • llvm/test/Transforms/InstCombine

1 file changed

+275
-0
lines changed

llvm/test/Transforms/InstCombine/ldexp.ll

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,3 +324,278 @@ define float @select_ldexp_f32_sameval_differentexp_types(i1 %cond, float %val,
324324
%select = select i1 %cond, float %ldexp0, float %ldexp1
325325
ret float %select
326326
}
327+
328+
;---------------------------------------------------------------------
329+
; ldexp(ldexp(x, a), b) -> ldexp(x, a + b)
330+
;---------------------------------------------------------------------
331+
332+
define float @ldexp_ldexp(float %x, i32 %a, i32 %b) {
333+
; CHECK-LABEL: define float @ldexp_ldexp
334+
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
335+
; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
336+
; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
337+
; CHECK-NEXT: ret float [[LDEXP1]]
338+
;
339+
%ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
340+
%ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
341+
ret float %ldexp1
342+
}
343+
344+
define float @ldexp_reassoc_ldexp(float %x, i32 %a, i32 %b) {
345+
; CHECK-LABEL: define float @ldexp_reassoc_ldexp
346+
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
347+
; CHECK-NEXT: [[LDEXP0:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
348+
; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
349+
; CHECK-NEXT: ret float [[LDEXP1]]
350+
;
351+
%ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 %a)
352+
%ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
353+
ret float %ldexp1
354+
}
355+
356+
define float @ldexp_ldexp_reassoc(float %x, i32 %a, i32 %b) {
357+
; CHECK-LABEL: define float @ldexp_ldexp_reassoc
358+
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
359+
; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
360+
; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
361+
; CHECK-NEXT: ret float [[LDEXP1]]
362+
;
363+
%ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
364+
%ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
365+
ret float %ldexp1
366+
}
367+
368+
define float @ldexp_reassoc_ldexp_reassoc(float %x, i32 %a, i32 %b) {
369+
; CHECK-LABEL: define float @ldexp_reassoc_ldexp_reassoc
370+
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
371+
; CHECK-NEXT: [[LDEXP0:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
372+
; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
373+
; CHECK-NEXT: ret float [[LDEXP1]]
374+
;
375+
%ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 %a)
376+
%ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
377+
ret float %ldexp1
378+
}
379+
380+
; Test that we or the inner and outer flags
381+
define float @ldexp_reassoc_ldexp_reassoc_preserve_flags(float %x, i32 %a, i32 %b) {
382+
; CHECK-LABEL: define float @ldexp_reassoc_ldexp_reassoc_preserve_flags
383+
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
384+
; CHECK-NEXT: [[LDEXP0:%.*]] = call reassoc ninf float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
385+
; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc nnan float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
386+
; CHECK-NEXT: ret float [[LDEXP1]]
387+
;
388+
%ldexp0 = call reassoc ninf float @llvm.ldexp.f32.i32(float %x, i32 %a)
389+
%ldexp1 = call reassoc nnan float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
390+
ret float %ldexp1
391+
}
392+
393+
define <2 x float> @ldexp_reassoc_ldexp_reassoc_vec(<2 x float> %x, <2 x i32> %a, <2 x i32> %b) {
394+
; CHECK-LABEL: define <2 x float> @ldexp_reassoc_ldexp_reassoc_vec
395+
; CHECK-SAME: (<2 x float> [[X:%.*]], <2 x i32> [[A:%.*]], <2 x i32> [[B:%.*]]) {
396+
; CHECK-NEXT: [[LDEXP0:%.*]] = call reassoc <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> [[A]])
397+
; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[LDEXP0]], <2 x i32> [[B]])
398+
; CHECK-NEXT: ret <2 x float> [[LDEXP1]]
399+
;
400+
%ldexp0 = call reassoc <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %x, <2 x i32> %a)
401+
%ldexp1 = call reassoc <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %ldexp0, <2 x i32> %b)
402+
ret <2 x float> %ldexp1
403+
}
404+
405+
define float @ldexp_multi_use_ldexp(float %x, i32 %a, i32 %b, ptr %ptr) {
406+
; CHECK-LABEL: define float @ldexp_multi_use_ldexp
407+
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]], ptr [[PTR:%.*]]) {
408+
; CHECK-NEXT: [[LDEXP0:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
409+
; CHECK-NEXT: store float [[LDEXP0]], ptr [[PTR]], align 4
410+
; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
411+
; CHECK-NEXT: ret float [[LDEXP1]]
412+
;
413+
%ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 %a)
414+
store float %ldexp0, ptr %ptr
415+
%ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
416+
ret float %ldexp1
417+
}
418+
419+
; Test edge case where the intrinsic is declared with different int types.
420+
define float @ldexp_ldexp_different_exp_type(float %x, i32 %a, i64 %b) {
421+
; CHECK-LABEL: define float @ldexp_ldexp_different_exp_type
422+
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i64 [[B:%.*]]) {
423+
; CHECK-NEXT: [[LDEXP0:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
424+
; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i64(float [[LDEXP0]], i64 [[B]])
425+
; CHECK-NEXT: ret float [[LDEXP1]]
426+
;
427+
%ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 %a)
428+
%ldexp1 = call reassoc float @llvm.ldexp.f32.i64(float %ldexp0, i64 %b)
429+
ret float %ldexp1
430+
}
431+
432+
define float @ldexp_ldexp_constants(float %x) {
433+
; CHECK-LABEL: define float @ldexp_ldexp_constants
434+
; CHECK-SAME: (float [[X:%.*]]) {
435+
; CHECK-NEXT: [[LDEXP0:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 8)
436+
; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 24)
437+
; CHECK-NEXT: ret float [[LDEXP1]]
438+
;
439+
%ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 8)
440+
%ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 24)
441+
ret float %ldexp1
442+
}
443+
444+
define float @ldexp_ldexp_opposite_constants(float %x) {
445+
; CHECK-LABEL: define float @ldexp_ldexp_opposite_constants
446+
; CHECK-SAME: (float [[X:%.*]]) {
447+
; CHECK-NEXT: [[LDEXP0:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 8)
448+
; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 -8)
449+
; CHECK-NEXT: ret float [[LDEXP1]]
450+
;
451+
%ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 8)
452+
%ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 -8)
453+
ret float %ldexp1
454+
}
455+
456+
define float @ldexp_ldexp_negated_variable_reassoc(float %x, i32 %a) {
457+
; CHECK-LABEL: define float @ldexp_ldexp_negated_variable_reassoc
458+
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]]) {
459+
; CHECK-NEXT: [[LDEXP0:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
460+
; CHECK-NEXT: [[NEG_A:%.*]] = sub i32 0, [[A]]
461+
; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[NEG_A]])
462+
; CHECK-NEXT: ret float [[LDEXP1]]
463+
;
464+
%ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 %a)
465+
%neg.a = sub i32 0, %a
466+
%ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 %neg.a)
467+
ret float %ldexp1
468+
}
469+
470+
define float @ldexp_ldexp_negated_variable(float %x, i32 %a) {
471+
; CHECK-LABEL: define float @ldexp_ldexp_negated_variable
472+
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]]) {
473+
; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
474+
; CHECK-NEXT: [[NEG_A:%.*]] = sub i32 0, [[A]]
475+
; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[NEG_A]])
476+
; CHECK-NEXT: ret float [[LDEXP1]]
477+
;
478+
%ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
479+
%neg.a = sub i32 0, %a
480+
%ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %neg.a)
481+
ret float %ldexp1
482+
}
483+
484+
define float @ldexp_ldexp_first_exp_known_positive(float %x, i32 %a.arg, i32 %b) {
485+
; CHECK-LABEL: define float @ldexp_ldexp_first_exp_known_positive
486+
; CHECK-SAME: (float [[X:%.*]], i32 [[A_ARG:%.*]], i32 [[B:%.*]]) {
487+
; CHECK-NEXT: [[A:%.*]] = and i32 [[A_ARG]], 127
488+
; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
489+
; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
490+
; CHECK-NEXT: ret float [[LDEXP1]]
491+
;
492+
%a = and i32 %a.arg, 127
493+
%ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
494+
%ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
495+
ret float %ldexp1
496+
}
497+
498+
define float @ldexp_ldexp_first_second_known_positive(float %x, i32 %a, i32 %b.arg) {
499+
; CHECK-LABEL: define float @ldexp_ldexp_first_second_known_positive
500+
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B_ARG:%.*]]) {
501+
; CHECK-NEXT: [[B:%.*]] = and i32 [[B_ARG]], 127
502+
; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
503+
; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
504+
; CHECK-NEXT: ret float [[LDEXP1]]
505+
;
506+
%b = and i32 %b.arg, 127
507+
%ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
508+
%ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
509+
ret float %ldexp1
510+
}
511+
512+
define float @ldexp_ldexp_both_exp_known_positive(float %x, i32 %a.arg, i32 %b.arg) {
513+
; CHECK-LABEL: define float @ldexp_ldexp_both_exp_known_positive
514+
; CHECK-SAME: (float [[X:%.*]], i32 [[A_ARG:%.*]], i32 [[B_ARG:%.*]]) {
515+
; CHECK-NEXT: [[A:%.*]] = and i32 [[A_ARG]], 127
516+
; CHECK-NEXT: [[B:%.*]] = and i32 [[B_ARG]], 127
517+
; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
518+
; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
519+
; CHECK-NEXT: ret float [[LDEXP1]]
520+
;
521+
%a = and i32 %a.arg, 127
522+
%b = and i32 %b.arg, 127
523+
%ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
524+
%ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
525+
ret float %ldexp1
526+
}
527+
528+
define float @ldexp_ldexp_both_exp_known_negative(float %x, ptr %a.ptr, ptr %b.ptr) {
529+
; CHECK-LABEL: define float @ldexp_ldexp_both_exp_known_negative
530+
; CHECK-SAME: (float [[X:%.*]], ptr [[A_PTR:%.*]], ptr [[B_PTR:%.*]]) {
531+
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[A_PTR]], align 4, !range [[RNG0:![0-9]+]]
532+
; CHECK-NEXT: [[B:%.*]] = load i32, ptr [[B_PTR]], align 4, !range [[RNG0]]
533+
; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
534+
; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
535+
; CHECK-NEXT: ret float [[LDEXP1]]
536+
;
537+
%a = load i32, ptr %a.ptr, !range !0
538+
%b = load i32, ptr %b.ptr, !range !0
539+
%ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
540+
%ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
541+
ret float %ldexp1
542+
}
543+
544+
define float @ldexp_ldexp_exp_known_negative_and_positive(float %x, ptr %a.ptr, ptr %b.ptr) {
545+
; CHECK-LABEL: define float @ldexp_ldexp_exp_known_negative_and_positive
546+
; CHECK-SAME: (float [[X:%.*]], ptr [[A_PTR:%.*]], ptr [[B_PTR:%.*]]) {
547+
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[A_PTR]], align 4, !range [[RNG0]]
548+
; CHECK-NEXT: [[B:%.*]] = load i32, ptr [[B_PTR]], align 4, !range [[RNG1:![0-9]+]]
549+
; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
550+
; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
551+
; CHECK-NEXT: ret float [[LDEXP1]]
552+
;
553+
%a = load i32, ptr %a.ptr, !range !0
554+
%b = load i32, ptr %b.ptr, !range !1
555+
%ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
556+
%ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
557+
ret float %ldexp1
558+
}
559+
560+
define float @ldexp_ldexp_exp_known_positive_and_negative(float %x, ptr %a.ptr, ptr %b.ptr) {
561+
; CHECK-LABEL: define float @ldexp_ldexp_exp_known_positive_and_negative
562+
; CHECK-SAME: (float [[X:%.*]], ptr [[A_PTR:%.*]], ptr [[B_PTR:%.*]]) {
563+
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[A_PTR]], align 4, !range [[RNG1]]
564+
; CHECK-NEXT: [[B:%.*]] = load i32, ptr [[B_PTR]], align 4, !range [[RNG0]]
565+
; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
566+
; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
567+
; CHECK-NEXT: ret float [[LDEXP1]]
568+
;
569+
%a = load i32, ptr %a.ptr, !range !1
570+
%b = load i32, ptr %b.ptr, !range !0
571+
%ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
572+
%ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
573+
ret float %ldexp1
574+
}
575+
576+
define float @ldexp_reassoc_ldexp_reassoc_0(float %x, i32 %y) {
577+
; CHECK-LABEL: define float @ldexp_reassoc_ldexp_reassoc_0
578+
; CHECK-SAME: (float [[X:%.*]], i32 [[Y:%.*]]) {
579+
; CHECK-NEXT: [[LDEXP0:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 0)
580+
; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[Y]])
581+
; CHECK-NEXT: ret float [[LDEXP1]]
582+
;
583+
%ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 0)
584+
%ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 %y)
585+
ret float %ldexp1
586+
}
587+
588+
define float @ldexp_ldexp_0(float %x, i32 %y) {
589+
; CHECK-LABEL: define float @ldexp_ldexp_0
590+
; CHECK-SAME: (float [[X:%.*]], i32 [[Y:%.*]]) {
591+
; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 0)
592+
; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[Y]])
593+
; CHECK-NEXT: ret float [[LDEXP1]]
594+
;
595+
%ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 0)
596+
%ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %y)
597+
ret float %ldexp1
598+
}
599+
600+
!0 = !{i32 -127, i32 0}
601+
!1 = !{i32 0, i32 127}

0 commit comments

Comments
 (0)