@@ -377,3 +377,347 @@ define void @test11(ptr addrspace(1) nocapture dereferenceable(80) %P) {
377
377
378
378
declare void @f1 (ptr nocapture sret (%struct.big ))
379
379
declare void @f2 (ptr )
380
+
381
+ declare void @f (ptr )
382
+ declare void @f_byval (ptr byval (i32 ))
383
+ declare void @f_full_readonly (ptr nocapture noalias readonly )
384
+
385
+ define void @immut_param (ptr align 4 noalias %val ) {
386
+ ; CHECK-LABEL: @immut_param(
387
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly align 4 [[VAL:%.*]])
388
+ ; CHECK-NEXT: ret void
389
+ ;
390
+ %val1 = alloca i8 , align 4
391
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
392
+ call void @f (ptr align 4 nocapture noalias readonly %val1 )
393
+ ret void
394
+ }
395
+
396
+ ; Can't remove memcpy because dest may be captured.
397
+ define void @immut_param_maycapture (ptr align 4 noalias %val ) {
398
+ ; CHECK-LABEL: @immut_param_maycapture(
399
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
400
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 false)
401
+ ; CHECK-NEXT: call void @f(ptr noalias readonly align 4 [[VAL1]])
402
+ ; CHECK-NEXT: ret void
403
+ ;
404
+ %val1 = alloca i8 , align 4
405
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
406
+ call void @f (ptr align 4 noalias readonly %val1 )
407
+ ret void
408
+ }
409
+
410
+ ; Can't remove memcpy because dest may be aliased.
411
+ define void @immut_param_mayalias (ptr align 4 noalias %val ) {
412
+ ; CHECK-LABEL: @immut_param_mayalias(
413
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
414
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 false)
415
+ ; CHECK-NEXT: call void @f(ptr nocapture readonly align 4 [[VAL1]])
416
+ ; CHECK-NEXT: ret void
417
+ ;
418
+ %val1 = alloca i8 , align 4
419
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
420
+ call void @f (ptr align 4 nocapture readonly %val1 )
421
+ ret void
422
+ }
423
+
424
+ ; Can't remove memcpy because dest may be written.
425
+ define void @immut_param_maywrite (ptr align 4 noalias %val ) {
426
+ ; CHECK-LABEL: @immut_param_maywrite(
427
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
428
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 false)
429
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture align 4 [[VAL1]])
430
+ ; CHECK-NEXT: ret void
431
+ ;
432
+ %val1 = alloca i8 , align 4
433
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
434
+ call void @f (ptr align 4 nocapture noalias %val1 )
435
+ ret void
436
+ }
437
+
438
+ define void @immut_param_readonly (ptr align 4 noalias %val ) {
439
+ ; CHECK-LABEL: @immut_param_readonly(
440
+ ; CHECK-NEXT: call void @f_full_readonly(ptr align 4 [[VAL:%.*]])
441
+ ; CHECK-NEXT: ret void
442
+ ;
443
+ %val1 = alloca i8 , align 4
444
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
445
+ call void @f_full_readonly (ptr align 4 %val1 )
446
+ ret void
447
+ }
448
+
449
+ define void @immut_param_no_align (ptr align 4 noalias %val ) {
450
+ ; CHECK-LABEL: @immut_param_no_align(
451
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly [[VAL:%.*]])
452
+ ; CHECK-NEXT: ret void
453
+ ;
454
+ %val1 = alloca i8 , align 4
455
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
456
+ call void @f (ptr nocapture noalias readonly %val1 )
457
+ ret void
458
+ }
459
+
460
+ @gp = external constant [0 x i8 ]
461
+ ; Can't remove memcpy because dest is not unescaped alloca, so cpying is meaningfull.
462
+ define void @immut_param_global (ptr align 4 noalias %val ) {
463
+ ; CHECK-LABEL: @immut_param_global(
464
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 @gp, ptr align 4 [[VAL:%.*]], i64 1, i1 false)
465
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly align 4 @gp)
466
+ ; CHECK-NEXT: ret void
467
+ ;
468
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 @gp , ptr align 4 %val , i64 1 , i1 false )
469
+ call void @f (ptr nocapture align 4 noalias readonly @gp )
470
+ ret void
471
+ }
472
+
473
+ ; Can't remove memcpy for VLA because of unknown size and alignment.
474
+ define void @immut_param_vla (ptr align 4 noalias %val , i64 %n ) {
475
+ ; CHECK-LABEL: @immut_param_vla(
476
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca ptr, i64 [[N:%.*]], align 4
477
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 false)
478
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly align 4 [[VAL1]])
479
+ ; CHECK-NEXT: ret void
480
+ ;
481
+ %val1 = alloca ptr , i64 %n
482
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
483
+ call void @f (ptr nocapture align 4 noalias readonly %val1 )
484
+ ret void
485
+ }
486
+
487
+ ; Can't remove memcpy for scalable vector, because of memcpy size sufficiency is unknown
488
+ define void @immut_param_scalable_vector (ptr align 4 noalias %val ) {
489
+ ; CHECK-LABEL: @immut_param_scalable_vector(
490
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca <vscale x 2 x i32>, align 8
491
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 2, i1 false)
492
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly align 4 [[VAL1]])
493
+ ; CHECK-NEXT: ret void
494
+ ;
495
+ %val1 = alloca <vscale x 2 x i32 >
496
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 2 , i1 false )
497
+ call void @f (ptr nocapture align 4 noalias readonly %val1 )
498
+ ret void
499
+ }
500
+
501
+ ; Can't remove memcpy because dst is modified between call and memcpy
502
+ define void @immut_param_modified_dst (ptr align 4 noalias %val ) {
503
+ ; CHECK-LABEL: @immut_param_modified_dst(
504
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
505
+ ; CHECK-NEXT: store i32 13, ptr [[VAL1]], align 4
506
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly align 4 [[VAL1]])
507
+ ; CHECK-NEXT: ret void
508
+ ;
509
+ %val1 = alloca i8 , align 4
510
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
511
+ store i32 13 , ptr %val1
512
+ call void @f (ptr nocapture align 4 noalias readonly %val1 )
513
+ ret void
514
+ }
515
+
516
+ ; Can't remove memcpy because src is modified between call and memcpy
517
+ define void @immut_param_modified_src (ptr align 4 noalias %val ) {
518
+ ; CHECK-LABEL: @immut_param_modified_src(
519
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
520
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 false)
521
+ ; CHECK-NEXT: store i32 13, ptr [[VAL]], align 4
522
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly align 4 [[VAL1]])
523
+ ; CHECK-NEXT: ret void
524
+ ;
525
+ %val1 = alloca i8 , align 4
526
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
527
+ store i32 13 , ptr %val
528
+ call void @f (ptr nocapture align 4 noalias readonly %val1 )
529
+ ret void
530
+ }
531
+
532
+ ; Can't remove memcpy because memcpy is volatile
533
+ define void @immut_param_volatile (ptr align 4 noalias %val ) {
534
+ ; CHECK-LABEL: @immut_param_volatile(
535
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
536
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 true)
537
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly align 4 [[VAL1]])
538
+ ; CHECK-NEXT: ret void
539
+ ;
540
+ %val1 = alloca i8 , align 4
541
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 true )
542
+ call void @f (ptr nocapture align 4 noalias readonly %val1 )
543
+ ret void
544
+ }
545
+
546
+ ; Can't remove memcpy because address spaces are different.
547
+ define void @immut_param_different_addrespace (ptr addrspace (1 ) align 4 noalias %val ) {
548
+ ; CHECK-LABEL: @immut_param_different_addrespace(
549
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
550
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p1.i64(ptr align 4 [[VAL1]], ptr addrspace(1) align 4 [[VAL:%.*]], i64 1, i1 false)
551
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly align 4 [[VAL1]])
552
+ ; CHECK-NEXT: ret void
553
+ ;
554
+ %val1 = alloca i8 , align 4
555
+ call void @llvm.memcpy.p0.p1.i64 (ptr align 4 %val1 , ptr addrspace (1 ) align 4 %val , i64 1 , i1 false )
556
+ call void @f (ptr nocapture align 4 noalias readonly %val1 )
557
+ ret void
558
+ }
559
+
560
+ define void @immut_param_bigger_align (ptr align 16 noalias %val ) {
561
+ ; CHECK-LABEL: @immut_param_bigger_align(
562
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly [[VAL:%.*]])
563
+ ; CHECK-NEXT: ret void
564
+ ;
565
+ %val1 = alloca i8 , align 4
566
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr %val , i64 1 , i1 false )
567
+ call void @f (ptr nocapture noalias readonly %val1 )
568
+ ret void
569
+ }
570
+
571
+ ; Can't remove memcpy if we remove, the bigger alignment couldn't replaced by smaller one.
572
+ define void @immut_param_smaller_align (ptr align 4 noalias %val ) {
573
+ ; CHECK-LABEL: @immut_param_smaller_align(
574
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 16
575
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 16 [[VAL1]], ptr [[VAL:%.*]], i64 1, i1 false)
576
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly [[VAL1]])
577
+ ; CHECK-NEXT: ret void
578
+ ;
579
+ %val1 = alloca i8 , align 16
580
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 16 %val1 , ptr %val , i64 1 , i1 false )
581
+ call void @f (ptr nocapture noalias readonly %val1 )
582
+ ret void
583
+ }
584
+
585
+ define void @immut_param_enforced_alignment () {
586
+ ; CHECK-LABEL: @immut_param_enforced_alignment(
587
+ ; CHECK-NEXT: [[VAL:%.*]] = alloca i8, align 4
588
+ ; CHECK-NEXT: store i32 42, ptr [[VAL]], align 4
589
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly [[VAL]])
590
+ ; CHECK-NEXT: ret void
591
+ ;
592
+ %val = alloca i8 , align 1
593
+ store i32 42 , ptr %val
594
+ %val1 = alloca i8 , align 4
595
+ call void @llvm.memcpy.p0.p0.i64 (ptr %val1 , ptr %val , i64 1 , i1 false )
596
+ call void @f (ptr nocapture noalias readonly %val1 )
597
+ ret void
598
+ }
599
+
600
+ ; Can't remove memcpy, because if the %val directly passed to @f,
601
+ ; alignment of ptr to f's argument will be different.
602
+ define void @immut_invalid_align_branched (i1 %c , ptr noalias %val ) {
603
+ ; CHECK-LABEL: @immut_invalid_align_branched(
604
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca [4 x i8], align 4
605
+ ; CHECK-NEXT: [[VAL2:%.*]] = alloca [16 x i8], align 16
606
+ ; CHECK-NEXT: [[VAL3:%.*]] = select i1 [[C:%.*]], ptr [[VAL1]], ptr [[VAL2]]
607
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL3]], ptr align 4 [[VAL:%.*]], i64 4, i1 false)
608
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly [[VAL3]])
609
+ ; CHECK-NEXT: ret void
610
+ ;
611
+ %val1 = alloca [4 x i8 ], align 4
612
+ %val2 = alloca [16 x i8 ], align 16
613
+ %val3 = select i1 %c , ptr %val1 , ptr %val2
614
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val3 , ptr align 4 %val , i64 4 , i1 false )
615
+ call void @f (ptr nocapture noalias readonly %val3 )
616
+ ret void
617
+ }
618
+
619
+ ; Can't remove memcpy, because alias might modify the src.
620
+ define void @immut_but_alias_src (ptr %val ) {
621
+ ; CHECK-LABEL: @immut_but_alias_src(
622
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
623
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 false)
624
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly [[VAL1]])
625
+ ; CHECK-NEXT: ret void
626
+ ;
627
+ %val1 = alloca i8 , align 4
628
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
629
+ call void @f (ptr nocapture noalias readonly %val1 )
630
+ ret void
631
+ }
632
+
633
+ define void @immut_unescaped_alloca () {
634
+ ; CHECK-LABEL: @immut_unescaped_alloca(
635
+ ; CHECK-NEXT: [[VAL:%.*]] = alloca i8, align 4
636
+ ; CHECK-NEXT: store i32 42, ptr [[VAL]], align 4
637
+ ; CHECK-NEXT: call void @f_full_readonly(ptr [[VAL]])
638
+ ; CHECK-NEXT: ret void
639
+ ;
640
+ %val = alloca i8 , align 4
641
+ store i32 42 , ptr %val
642
+ %val1 = alloca i8 , align 4
643
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
644
+ call void @f_full_readonly (ptr %val1 )
645
+ ret void
646
+ }
647
+
648
+ ; Can't remove memcpy, because alloca src is modified
649
+ define void @immut_unescaped_alloca_modified () {
650
+ ; CHECK-LABEL: @immut_unescaped_alloca_modified(
651
+ ; CHECK-NEXT: [[VAL:%.*]] = alloca i8, align 4
652
+ ; CHECK-NEXT: store i32 42, ptr [[VAL]], align 4
653
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4
654
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL]], i64 1, i1 false)
655
+ ; CHECK-NEXT: call void @f_full_readonly(ptr [[VAL1]])
656
+ ; CHECK-NEXT: ret void
657
+ ;
658
+ %val = alloca i8 , align 4
659
+ store i32 42 , ptr %val
660
+ %val1 = alloca i8 , align 4
661
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val1 , ptr align 4 %val , i64 1 , i1 false )
662
+ store i32 13 , ptr %val
663
+ call void @f_full_readonly (ptr %val1 )
664
+ ret void
665
+ }
666
+
667
+ ; TODO: Remove memcpy
668
+ define void @immut_valid_align_branched (i1 %c , ptr noalias align 4 %val ) {
669
+ ; CHECK-LABEL: @immut_valid_align_branched(
670
+ ; CHECK-NEXT: [[VAL1:%.*]] = alloca [4 x i8], align 4
671
+ ; CHECK-NEXT: [[VAL2:%.*]] = alloca [16 x i8], align 4
672
+ ; CHECK-NEXT: [[VAL3:%.*]] = select i1 [[C:%.*]], ptr [[VAL1]], ptr [[VAL2]]
673
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL3]], ptr align 4 [[VAL:%.*]], i64 4, i1 false)
674
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly [[VAL3]])
675
+ ; CHECK-NEXT: ret void
676
+ ;
677
+ %val1 = alloca [4 x i8 ], align 4
678
+ %val2 = alloca [16 x i8 ], align 4
679
+ %val3 = select i1 %c , ptr %val1 , ptr %val2
680
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %val3 , ptr align 4 %val , i64 4 , i1 false )
681
+ call void @f (ptr nocapture noalias readonly %val3 )
682
+ ret void
683
+ }
684
+
685
+ ; Merge/drop noalias metadata when replacing parameter.
686
+ define void @immut_param_noalias_metadata (ptr align 4 byval (i32 ) %ptr ) {
687
+ ; CHECK-LABEL: @immut_param_noalias_metadata(
688
+ ; CHECK-NEXT: store i32 1, ptr [[PTR:%.*]], align 4, !noalias !0
689
+ ; CHECK-NEXT: call void @f(ptr noalias nocapture readonly [[PTR]])
690
+ ; CHECK-NEXT: ret void
691
+ ;
692
+ %tmp = alloca i32 , align 4
693
+ store i32 1 , ptr %ptr , !noalias !2
694
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %tmp , ptr align 4 %ptr , i64 4 , i1 false )
695
+ call void @f (ptr nocapture noalias readonly %tmp ), !alias.scope !2
696
+ ret void
697
+ }
698
+
699
+ define void @byval_param_noalias_metadata (ptr align 4 byval (i32 ) %ptr ) {
700
+ ; CHECK-LABEL: @byval_param_noalias_metadata(
701
+ ; CHECK-NEXT: store i32 1, ptr [[PTR:%.*]], align 4, !noalias !0
702
+ ; CHECK-NEXT: call void @f_byval(ptr byval(i32) align 4 [[PTR]])
703
+ ; CHECK-NEXT: ret void
704
+ ;
705
+ %tmp = alloca i32 , align 4
706
+ store i32 1 , ptr %ptr , !noalias !2
707
+ call void @llvm.memcpy.p0.p0.i64 (ptr align 4 %tmp , ptr align 4 %ptr , i64 4 , i1 false )
708
+ call void @f_byval (ptr align 4 byval (i32 ) %tmp ), !alias.scope !2
709
+ ret void
710
+ }
711
+
712
+ define void @memcpy_memory_none (ptr %p , ptr %p2 , i64 %size ) {
713
+ ; CHECK-LABEL: @memcpy_memory_none(
714
+ ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[P:%.*]], ptr [[P2:%.*]], i64 [[SIZE:%.*]], i1 false) #[[ATTR6:[0-9]+]]
715
+ ; CHECK-NEXT: ret void
716
+ ;
717
+ call void @llvm.memcpy.p0.p0.i64 (ptr %p , ptr %p2 , i64 %size , i1 false ) memory(none)
718
+ ret void
719
+ }
720
+
721
+ !0 = !{!0 }
722
+ !1 = !{!1 , !0 }
723
+ !2 = !{!1 }
0 commit comments