Skip to content

Commit 3c83f17

Browse files
authored
Backport llvm@5c3beb7 (#22)
to avoid non integral addresspace issues
1 parent 47769d3 commit 3c83f17

File tree

2 files changed

+352
-3
lines changed

2 files changed

+352
-3
lines changed

llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,6 +1455,13 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) {
14551455
eraseInstruction(M);
14561456
return true;
14571457
}
1458+
// If the size is zero, remove the memcpy. This also prevents infinite loops
1459+
// in processMemSetMemCpyDependence, which is a no-op for zero-length memcpys.
1460+
1461+
MemoryUseOrDef *MA = MSSA->getMemoryAccess(M);
1462+
if (!MA)
1463+
// Degenerate case: memcpy marked as not accessing memory.
1464+
return false;
14581465

14591466
// If copying from a constant, try to turn the memcpy into a memset.
14601467
if (auto *GV = dyn_cast<GlobalVariable>(M->getSource()))
@@ -1464,8 +1471,7 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) {
14641471
IRBuilder<> Builder(M);
14651472
Instruction *NewM = Builder.CreateMemSet(
14661473
M->getRawDest(), ByteVal, M->getLength(), M->getDestAlign(), false);
1467-
auto *LastDef =
1468-
cast<MemoryDef>(MSSAU->getMemorySSA()->getMemoryAccess(M));
1474+
auto *LastDef = cast<MemoryDef>(MA);
14691475
auto *NewAccess =
14701476
MSSAU->createMemoryAccessAfter(NewM, LastDef, LastDef);
14711477
MSSAU->insertDef(cast<MemoryDef>(NewAccess), /*RenameUses=*/true);
@@ -1476,7 +1482,6 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) {
14761482
}
14771483

14781484
BatchAAResults BAA(*AA);
1479-
MemoryUseOrDef *MA = MSSA->getMemoryAccess(M);
14801485
// FIXME: Not using getClobberingMemoryAccess() here due to PR54682.
14811486
MemoryAccess *AnyClobber = MA->getDefiningAccess();
14821487
MemoryLocation DestLoc = MemoryLocation::getForDest(M);

llvm/test/Transforms/MemCpyOpt/memcpy.ll

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,3 +377,347 @@ define void @test11(ptr addrspace(1) nocapture dereferenceable(80) %P) {
377377

378378
declare void @f1(ptr nocapture sret(%struct.big))
379379
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

Comments
 (0)