@@ -324,3 +324,278 @@ define float @select_ldexp_f32_sameval_differentexp_types(i1 %cond, float %val,
324
324
%select = select i1 %cond , float %ldexp0 , float %ldexp1
325
325
ret float %select
326
326
}
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