brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.6 KiB · 0970ed3 Raw
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