206 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -passes=memcpyopt -S %s -verify-memoryssa | FileCheck %s3 4; memset -> memcpy forwarding, if memcpy is larger than memset, but trailing5; bytes are known to be undef.6 7 8%T = type { i64, i32, i32 }9 10define void @test_alloca(ptr %result) {11; CHECK-LABEL: @test_alloca(12; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 813; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[A]], i8 0, i64 12, i1 false)14; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[RESULT:%.*]], i8 0, i64 12, i1 false)15; CHECK-NEXT: ret void16;17 %a = alloca %T, align 818 call void @llvm.memset.p0.i64(ptr align 8 %a, i8 0, i64 12, i1 false)19 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %a, i64 16, i1 false)20 ret void21}22 23define void @test_alloca_with_lifetimes(ptr %result) {24; CHECK-LABEL: @test_alloca_with_lifetimes(25; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 826; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A]])27; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[A]], i8 0, i64 12, i1 false)28; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[RESULT:%.*]], i8 0, i64 12, i1 false)29; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A]])30; CHECK-NEXT: ret void31;32 %a = alloca %T, align 833 call void @llvm.lifetime.start.p0(ptr %a)34 call void @llvm.memset.p0.i64(ptr align 8 %a, i8 0, i64 12, i1 false)35 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %a, i64 16, i1 false)36 call void @llvm.lifetime.end.p0(ptr %a)37 ret void38}39 40; The trailing bytes are not known to be undef, we can't ignore them.41define void @test_not_undef_memory(ptr %result, ptr %input) {42; CHECK-LABEL: @test_not_undef_memory(43; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[INPUT:%.*]], i8 0, i64 12, i1 false)44; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[RESULT:%.*]], ptr align 8 [[INPUT]], i64 16, i1 false)45; CHECK-NEXT: ret void46;47 call void @llvm.memset.p0.i64(ptr align 8 %input, i8 0, i64 12, i1 false)48 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %input, i64 16, i1 false)49 ret void50}51 52; Memset is volatile, memcpy is not. Can be optimized.53define void @test_volatile_memset(ptr %result) {54; CHECK-LABEL: @test_volatile_memset(55; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 856; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[A]], i8 0, i64 12, i1 true)57; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[RESULT:%.*]], i8 0, i64 12, i1 false)58; CHECK-NEXT: ret void59;60 %a = alloca %T, align 861 call void @llvm.memset.p0.i64(ptr align 8 %a, i8 0, i64 12, i1 true)62 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %a, i64 16, i1 false)63 ret void64}65 66; Memcpy is volatile, memset is not. Cannot be optimized.67define void @test_volatile_memcpy(ptr %result) {68; CHECK-LABEL: @test_volatile_memcpy(69; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 870; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[A]], i8 0, i64 12, i1 false)71; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[RESULT:%.*]], ptr align 8 [[A]], i64 16, i1 true)72; CHECK-NEXT: ret void73;74 %a = alloca %T, align 875 call void @llvm.memset.p0.i64(ptr align 8 %a, i8 0, i64 12, i1 false)76 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %a, i64 16, i1 true)77 ret void78}79 80; Write between memset and memcpy, can't optimize.81define void @test_write_between(ptr %result) {82; CHECK-LABEL: @test_write_between(83; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 884; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[A]], i8 0, i64 12, i1 false)85; CHECK-NEXT: store i8 -1, ptr [[A]], align 186; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[RESULT:%.*]], ptr align 8 [[A]], i64 16, i1 false)87; CHECK-NEXT: ret void88;89 %a = alloca %T, align 890 call void @llvm.memset.p0.i64(ptr align 8 %a, i8 0, i64 12, i1 false)91 store i8 -1, ptr %a92 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %a, i64 16, i1 false)93 ret void94}95 96; A write prior to the memset, which is part of the memset region.97; We could optimize this, but currently don't, because the used memory location is imprecise.98define void @test_write_before_memset_in_memset_region(ptr %result) {99; CHECK-LABEL: @test_write_before_memset_in_memset_region(100; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 8101; CHECK-NEXT: store i8 -1, ptr [[A]], align 1102; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[A]], i8 0, i64 8, i1 false)103; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[RESULT:%.*]], ptr align 8 [[A]], i64 16, i1 false)104; CHECK-NEXT: ret void105;106 %a = alloca %T, align 8107 store i8 -1, ptr %a108 call void @llvm.memset.p0.i64(ptr align 8 %a, i8 0, i64 8, i1 false)109 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %a, i64 16, i1 false)110 ret void111}112 113; A write prior to the memset, which is part of the memcpy (but not memset) region.114; This cannot be optimized.115define void @test_write_before_memset_in_memcpy_region(ptr %result) {116; CHECK-LABEL: @test_write_before_memset_in_memcpy_region(117; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 8118; CHECK-NEXT: [[C:%.*]] = getelementptr inbounds [[T]], ptr [[A]], i64 0, i32 2119; CHECK-NEXT: store i32 -1, ptr [[C]], align 4120; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[A]], i8 0, i64 8, i1 false)121; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[RESULT:%.*]], ptr align 8 [[A]], i64 16, i1 false)122; CHECK-NEXT: ret void123;124 %a = alloca %T, align 8125 %c = getelementptr inbounds %T, ptr %a, i64 0, i32 2126 store i32 -1, ptr %c127 call void @llvm.memset.p0.i64(ptr align 8 %a, i8 0, i64 8, i1 false)128 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %a, i64 16, i1 false)129 ret void130}131 132; A write prior to the memset, which is part of both the memset and memcpy regions.133; This cannot be optimized.134define void @test_write_before_memset_in_both_regions(ptr %result) {135; CHECK-LABEL: @test_write_before_memset_in_both_regions(136; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 8137; CHECK-NEXT: [[C:%.*]] = getelementptr inbounds [[T]], ptr [[A]], i64 0, i32 1138; CHECK-NEXT: store i32 -1, ptr [[C]], align 4139; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[A]], i8 0, i64 10, i1 false)140; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[RESULT:%.*]], ptr align 8 [[A]], i64 16, i1 false)141; CHECK-NEXT: ret void142;143 %a = alloca %T, align 8144 %c = getelementptr inbounds %T, ptr %a, i64 0, i32 1145 store i32 -1, ptr %c146 call void @llvm.memset.p0.i64(ptr align 8 %a, i8 0, i64 10, i1 false)147 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %a, i64 16, i1 false)148 ret void149}150 151define void @test_negative_offset_memset(ptr %result) {152; CHECK-LABEL: @test_negative_offset_memset(153; CHECK-NEXT: [[A1:%.*]] = alloca [16 x i8], align 8154; CHECK-NEXT: [[A:%.*]] = getelementptr i8, ptr [[A1]], i32 4155; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[A]], i8 0, i64 12, i1 false)156; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[RESULT:%.*]], ptr align 8 [[A1]], i64 12, i1 false)157; CHECK-NEXT: ret void158;159 %a = alloca [ 16 x i8 ], align 8160 %b = getelementptr i8, ptr %a, i32 4161 call void @llvm.memset.p0.i64(ptr align 8 %b, i8 0, i64 12, i1 false)162 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %a, i64 12, i1 false)163 ret void164}165 166define void @test_offset_memsetcpy(ptr %result) {167; CHECK-LABEL: @test_offset_memsetcpy(168; CHECK-NEXT: [[A1:%.*]] = alloca [16 x i8], align 8169; CHECK-NEXT: [[A:%.*]] = getelementptr i8, ptr [[A1]], i32 4170; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[A1]], i8 0, i64 12, i1 false)171; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[RESULT:%.*]], i8 0, i64 8, i1 false)172; CHECK-NEXT: ret void173;174 %a = alloca [ 16 x i8 ], align 8175 %b = getelementptr i8, ptr %a, i32 4176 call void @llvm.memset.p0.i64(ptr align 8 %a, i8 0, i64 12, i1 false)177 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %b, i64 12, i1 false)178 ret void179}180 181define void @test_two_memset(ptr %result) {182; CHECK-LABEL: @test_two_memset(183; CHECK-NEXT: [[A:%.*]] = alloca [16 x i8], align 8184; CHECK-NEXT: [[B:%.*]] = getelementptr i8, ptr [[A]], i32 12185; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[A]], i8 0, i64 12, i1 false)186; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[B]], i8 1, i64 4, i1 false)187; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[RESULT:%.*]], ptr align 8 [[A]], i64 16, i1 false)188; CHECK-NEXT: ret void189;190 %a = alloca [ 16 x i8 ], align 8191 %b = getelementptr i8, ptr %a, i32 12192 call void @llvm.memset.p0.i64(ptr align 8 %a, i8 0, i64 12, i1 false)193 call void @llvm.memset.p0.i64(ptr align 8 %b, i8 1, i64 4, i1 false)194 call void @llvm.memcpy.p0.p0.i64(ptr %result, ptr align 8 %a, i64 16, i1 false)195 ret void196}197 198declare ptr @malloc(i64)199declare void @free(ptr)200 201declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1)202declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture readonly, i64, i1)203 204declare void @llvm.lifetime.start.p0(ptr nocapture)205declare void @llvm.lifetime.end.p0(ptr nocapture)206