321 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -passes=dse -S < %s | FileCheck %s3 4declare void @llvm.lifetime.start.p0(ptr nocapture)5declare void @llvm.lifetime.end.p0(ptr nocapture)6 7declare void @unknown()8declare void @f(ptr)9declare void @f2(ptr, ptr)10declare ptr @f3(ptr, ptr)11 12; Basic case for DSEing a trivially dead writing call13define void @test_dead() {14; CHECK-LABEL: @test_dead(15; CHECK-NEXT: ret void16;17 %a = alloca i32, align 418 call void @f(ptr writeonly nocapture %a) argmemonly nounwind willreturn19 ret void20}21 22; Add in canonical lifetime intrinsics23define void @test_lifetime() {24; CHECK-LABEL: @test_lifetime(25; CHECK-NEXT: [[A:%.*]] = alloca i32, align 426; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A]])27; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A]])28; CHECK-NEXT: ret void29;30 %a = alloca i32, align 431 call void @llvm.lifetime.start.p0(ptr %a)32 call void @f(ptr writeonly nocapture %a) argmemonly nounwind willreturn33 call void @llvm.lifetime.end.p0(ptr %a)34 ret void35}36 37; Add some unknown calls just to point out that this is use based, not38; instruction order sensitive39define void @test_lifetime2() {40; CHECK-LABEL: @test_lifetime2(41; CHECK-NEXT: [[A:%.*]] = alloca i32, align 442; CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[A]])43; CHECK-NEXT: call void @unknown()44; CHECK-NEXT: call void @unknown()45; CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr [[A]])46; CHECK-NEXT: ret void47;48 %a = alloca i32, align 449 call void @llvm.lifetime.start.p0(ptr %a)50 call void @unknown()51 call void @f(ptr writeonly nocapture %a) argmemonly nounwind willreturn52 call void @unknown()53 call void @llvm.lifetime.end.p0(ptr %a)54 ret void55}56 57; As long as the result is unused, we can even remove reads of the alloca58; itself since the write will be dropped.59define void @test_dead_readwrite() {60; CHECK-LABEL: @test_dead_readwrite(61; CHECK-NEXT: ret void62;63 %a = alloca i32, align 464 call void @f(ptr nocapture %a) argmemonly nounwind willreturn65 ret void66}67 68define i32 @test_neg_read_after() {69; CHECK-LABEL: @test_neg_read_after(70; CHECK-NEXT: [[A:%.*]] = alloca i32, align 471; CHECK-NEXT: call void @f(ptr writeonly captures(none) [[A]]) #[[ATTR1:[0-9]+]]72; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[A]], align 473; CHECK-NEXT: ret i32 [[RES]]74;75 %a = alloca i32, align 476 call void @f(ptr writeonly nocapture %a) argmemonly nounwind willreturn77 %res = load i32, ptr %a78 ret i32 %res79}80 81 82define void @test_neg_infinite_loop() {83; CHECK-LABEL: @test_neg_infinite_loop(84; CHECK-NEXT: [[A:%.*]] = alloca i32, align 485; CHECK-NEXT: call void @f(ptr writeonly captures(none) [[A]]) #[[ATTR2:[0-9]+]]86; CHECK-NEXT: ret void87;88 %a = alloca i32, align 489 call void @f(ptr writeonly nocapture %a) argmemonly nounwind90 ret void91}92 93define void @test_neg_throw() {94; CHECK-LABEL: @test_neg_throw(95; CHECK-NEXT: [[A:%.*]] = alloca i32, align 496; CHECK-NEXT: call void @f(ptr writeonly captures(none) [[A]]) #[[ATTR3:[0-9]+]]97; CHECK-NEXT: ret void98;99 %a = alloca i32, align 4100 call void @f(ptr writeonly nocapture %a) argmemonly willreturn101 ret void102}103 104define void @test_neg_extra_write() {105; CHECK-LABEL: @test_neg_extra_write(106; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4107; CHECK-NEXT: call void @f(ptr writeonly captures(none) [[A]]) #[[ATTR4:[0-9]+]]108; CHECK-NEXT: ret void109;110 %a = alloca i32, align 4111 call void @f(ptr writeonly nocapture %a) nounwind willreturn112 ret void113}114 115; In this case, we can't remove a1 because we need to preserve the write to116; a2, and if we leave the call around, we need memory to pass to the first arg.117define void @test_neg_unmodeled_write() {118; CHECK-LABEL: @test_neg_unmodeled_write(119; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4120; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4121; CHECK-NEXT: call void @f2(ptr writeonly captures(none) [[A]], ptr [[A2]]) #[[ATTR1]]122; CHECK-NEXT: ret void123;124 %a = alloca i32, align 4125 %a2 = alloca i32, align 4126 call void @f2(ptr nocapture writeonly %a, ptr %a2) argmemonly nounwind willreturn127 ret void128}129 130define i32 @test_neg_captured_by_call() {131; CHECK-LABEL: @test_neg_captured_by_call(132; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4133; CHECK-NEXT: [[A2:%.*]] = alloca ptr, align 4134; CHECK-NEXT: call void @f2(ptr writeonly [[A]], ptr [[A2]]) #[[ATTR1]]135; CHECK-NEXT: [[A_COPY_CAST:%.*]] = load ptr, ptr [[A2]], align 8136; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[A_COPY_CAST]], align 4137; CHECK-NEXT: ret i32 [[RES]]138;139 %a = alloca i32, align 4140 %a2 = alloca ptr, align 4141 call void @f2(ptr writeonly %a, ptr %a2) argmemonly nounwind willreturn142 %a_copy_cast = load ptr, ptr %a2143 %res = load i32, ptr %a_copy_cast144 ret i32 %res145}146 147define i32 @test_neg_captured_before() {148; CHECK-LABEL: @test_neg_captured_before(149; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4150; CHECK-NEXT: [[A2:%.*]] = alloca ptr, align 4151; CHECK-NEXT: store ptr [[A]], ptr [[A2]], align 8152; CHECK-NEXT: call void @f(ptr writeonly captures(none) [[A]]) #[[ATTR1]]153; CHECK-NEXT: [[A_COPY_CAST:%.*]] = load ptr, ptr [[A2]], align 8154; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[A_COPY_CAST]], align 4155; CHECK-NEXT: ret i32 [[RES]]156;157 %a = alloca i32, align 4158 %a2 = alloca ptr, align 4159 store ptr %a, ptr %a2160 call void @f(ptr writeonly nocapture %a) argmemonly nounwind willreturn161 %a_copy_cast = load ptr, ptr %a2162 %res = load i32, ptr %a_copy_cast163 ret i32 %res164}165 166; Callee might be dead, but op bundle has unknown semantics and thus isn't.167define void @test_new_op_bundle() {168; CHECK-LABEL: @test_new_op_bundle(169; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4170; CHECK-NEXT: call void @f(ptr writeonly captures(none) [[A]]) #[[ATTR1]] [ "unknown"(ptr [[A]]) ]171; CHECK-NEXT: ret void172;173 %a = alloca i32, align 4174 call void @f(ptr writeonly nocapture %a) argmemonly nounwind willreturn ["unknown" (ptr %a)]175 ret void176}177 178; Show that reading from unrelated memory is okay179define void @test_unreleated_read() {180; CHECK-LABEL: @test_unreleated_read(181; CHECK-NEXT: ret void182;183 %a = alloca i32, align 4184 %a2 = alloca i32, align 4185 call void @f2(ptr nocapture writeonly %a, ptr nocapture readonly %a2) argmemonly nounwind willreturn186 ret void187}188 189; Removing a capture is also okay. The capture can only be in the return value190; (which is unused) or written into the dead out parameter.191define void @test_unrelated_capture() {192; CHECK-LABEL: @test_unrelated_capture(193; CHECK-NEXT: ret void194;195 %a = alloca i32, align 4196 %a2 = alloca i32, align 4197 call ptr @f3(ptr nocapture writeonly %a, ptr readonly %a2) argmemonly nounwind willreturn198 ret void199}200 201; Cannot remove call, as %a2 is captured via the return value.202define i8 @test_neg_unrelated_capture_used_via_return() {203; CHECK-LABEL: @test_neg_unrelated_capture_used_via_return(204; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4205; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4206; CHECK-NEXT: [[CAPTURE:%.*]] = call ptr @f3(ptr writeonly captures(none) [[A]], ptr readonly [[A2]]) #[[ATTR1]]207; CHECK-NEXT: [[V:%.*]] = load i8, ptr [[CAPTURE]], align 1208; CHECK-NEXT: ret i8 [[V]]209;210 %a = alloca i32, align 4211 %a2 = alloca i32, align 4212 %capture = call ptr @f3(ptr nocapture writeonly %a, ptr readonly %a2) argmemonly nounwind willreturn213 %v = load i8, ptr %capture214 ret i8 %v215}216 217; As long as the result is unused, we can even remove reads of the alloca218; itself since the write will be dropped.219define void @test_self_read() {220; CHECK-LABEL: @test_self_read(221; CHECK-NEXT: ret void222;223 %a = alloca i32, align 4224 call void @f2(ptr nocapture writeonly %a, ptr nocapture readonly %a) argmemonly nounwind willreturn225 ret void226}227 228; We can remove the call because while we don't know the size of the write done229; by the call, we do know the following store writes to the entire contents of230; the alloca.231define i32 @test_dse_overwrite() {232; CHECK-LABEL: @test_dse_overwrite(233; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4234; CHECK-NEXT: store i32 0, ptr [[A]], align 4235; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 4236; CHECK-NEXT: ret i32 [[V]]237;238 %a = alloca i32, align 4239 call void @f(ptr writeonly nocapture %a) argmemonly nounwind willreturn240 store i32 0, ptr %a241 %v = load i32, ptr %a242 ret i32 %v243}244 245; Negative case where we can read part of the value written by @f.246define i32 @test_neg_dse_partial_overwrite() {247; CHECK-LABEL: @test_neg_dse_partial_overwrite(248; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4249; CHECK-NEXT: call void @f(ptr writeonly captures(none) [[A]]) #[[ATTR1]]250; CHECK-NEXT: store i8 0, ptr [[A]], align 1251; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 4252; CHECK-NEXT: ret i32 [[V]]253;254 %a = alloca i32, align 4255 call void @f(ptr writeonly nocapture %a) argmemonly nounwind willreturn256 store i8 0, ptr %a257 %v = load i32, ptr %a258 ret i32 %v259}260 261; Negative case where we don't know the size of a, and thus can't use the262; full overwrite reasoning263define i32 @test_neg_dse_unsized(ptr %a) {264; CHECK-LABEL: @test_neg_dse_unsized(265; CHECK-NEXT: call void @f(ptr writeonly captures(none) [[A:%.*]]) #[[ATTR1]]266; CHECK-NEXT: store i32 0, ptr [[A]], align 4267; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 4268; CHECK-NEXT: ret i32 [[V]]269;270 call void @f(ptr writeonly nocapture %a) argmemonly nounwind willreturn271 store i32 0, ptr %a272 %v = load i32, ptr %a273 ret i32 %v274}275 276@G = global i8 0277 278; Same as test_dse_overwrite, but with a non-alloca object.279define void @test_dse_non_alloca() {280; CHECK-LABEL: @test_dse_non_alloca(281; CHECK-NEXT: store i8 0, ptr @G, align 1282; CHECK-NEXT: ret void283;284 call void @f(ptr writeonly nocapture @G) argmemonly nounwind willreturn285 store i8 0, ptr @G286 ret void287}288 289define void @test_other_read_effects() {290; CHECK-LABEL: @test_other_read_effects(291; CHECK-NEXT: ret void292;293 %a = alloca i32, align 4294 call void @f(ptr %a) memory(read, argmem: readwrite) nounwind willreturn295 ret void296}297 298define i32 @test_other_read_effects_read_after() {299; CHECK-LABEL: @test_other_read_effects_read_after(300; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4301; CHECK-NEXT: call void @f(ptr [[A]]) #[[ATTR5:[0-9]+]]302; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[A]], align 4303; CHECK-NEXT: ret i32 [[V]]304;305 %a = alloca i32, align 4306 call void @f(ptr %a) memory(read, argmem: readwrite) nounwind willreturn307 %v = load i32, ptr %a308 ret i32 %v309}310 311define void @test_other_write_effects() {312; CHECK-LABEL: @test_other_write_effects(313; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4314; CHECK-NEXT: call void @f(ptr [[A]]) #[[ATTR6:[0-9]+]]315; CHECK-NEXT: ret void316;317 %a = alloca i32, align 4318 call void @f(ptr %a) memory(write, argmem: readwrite) nounwind willreturn319 ret void320}321