| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,323 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s | ||
|
|
||
| target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" | ||
|
|
||
| declare noalias i8* @malloc(i64) | ||
|
|
||
| declare void @foo() | ||
| declare void @capture(i8*) | ||
|
|
||
| ; Check that we do not remove the second store, as %m is returned. | ||
| define i8* @test_return_captures_1() { | ||
| ; CHECK-LABEL: @test_return_captures_1( | ||
| ; CHECK-NEXT: [[M:%.*]] = call i8* @malloc(i64 24) | ||
| ; CHECK-NEXT: store i8 1, i8* [[M]] | ||
| ; CHECK-NEXT: ret i8* [[M]] | ||
| ; | ||
| %m = call i8* @malloc(i64 24) | ||
| store i8 0, i8* %m | ||
| store i8 1, i8* %m | ||
| ret i8* %m | ||
| } | ||
|
|
||
| ; Same as @test_return_captures_1, but across BBs. | ||
| define i8* @test_return_captures_2() { | ||
| ; CHECK-LABEL: @test_return_captures_2( | ||
| ; CHECK-NEXT: [[M:%.*]] = call i8* @malloc(i64 24) | ||
| ; CHECK-NEXT: store i8 0, i8* [[M]] | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: store i8 1, i8* [[M]] | ||
| ; CHECK-NEXT: ret i8* [[M]] | ||
| ; | ||
| %m = call i8* @malloc(i64 24) | ||
| store i8 0, i8* %m | ||
| br label %exit | ||
|
|
||
| exit: | ||
| store i8 1, i8* %m | ||
| ret i8* %m | ||
| } | ||
|
|
||
|
|
||
| %S1 = type { i8 * } | ||
|
|
||
| ; We cannot remove the last store to %m, because it escapes by storing it to %E. | ||
| define void @test_malloc_capture_1(%S1* %E) { | ||
| ; CHECK-LABEL: @test_malloc_capture_1( | ||
| ; CHECK-NEXT: [[M:%.*]] = call i8* @malloc(i64 24) | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: [[F_PTR:%.*]] = getelementptr [[S1:%.*]], %S1* [[E:%.*]], i32 0, i32 0 | ||
| ; CHECK-NEXT: store i8* [[M]], i8** [[F_PTR]] | ||
| ; CHECK-NEXT: store i8 1, i8* [[M]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %m = call i8* @malloc(i64 24) | ||
| br label %exit | ||
|
|
||
| exit: | ||
| %f.ptr = getelementptr %S1, %S1* %E, i32 0, i32 0 | ||
| store i8* %m, i8** %f.ptr | ||
| store i8 1, i8* %m | ||
| ret void | ||
| } | ||
|
|
||
| ; Check we do not eliminate either store. The first one cannot be eliminated, | ||
| ; due to the call of @capture. The second one because %m escapes. | ||
| define i8* @test_malloc_capture_2() { | ||
| ; CHECK-LABEL: @test_malloc_capture_2( | ||
| ; CHECK-NEXT: [[M:%.*]] = call i8* @malloc(i64 24) | ||
| ; CHECK-NEXT: store i8 0, i8* [[M]] | ||
| ; CHECK-NEXT: call void @capture(i8* [[M]]) | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: store i8 1, i8* [[M]] | ||
| ; CHECK-NEXT: ret i8* [[M]] | ||
| ; | ||
| %m = call i8* @malloc(i64 24) | ||
| store i8 0, i8* %m | ||
| call void @capture(i8* %m) | ||
| br label %exit | ||
|
|
||
| exit: | ||
| store i8 1, i8* %m | ||
| ret i8* %m | ||
| } | ||
|
|
||
| ; We can remove the first store store i8 0, i8* %m because there are no throwing | ||
| ; instructions between the 2 stores and also %m escapes after the killing store. | ||
| define i8* @test_malloc_capture_3() { | ||
| ; CHECK-LABEL: @test_malloc_capture_3( | ||
| ; CHECK-NEXT: [[M:%.*]] = call i8* @malloc(i64 24) | ||
| ; CHECK-NEXT: store i8 0, i8* [[M]] | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: store i8 1, i8* [[M]] | ||
| ; CHECK-NEXT: call void @capture(i8* [[M]]) | ||
| ; CHECK-NEXT: ret i8* [[M]] | ||
| ; | ||
| %m = call i8* @malloc(i64 24) | ||
| store i8 0, i8* %m | ||
| br label %exit | ||
|
|
||
| exit: | ||
| store i8 1, i8* %m | ||
| call void @capture(i8* %m) | ||
| ret i8* %m | ||
| } | ||
|
|
||
| ; TODO: We could remove the first store store i8 0, i8* %m because %m escapes | ||
| ; after the killing store. | ||
| define i8* @test_malloc_capture_4() { | ||
| ; CHECK-LABEL: @test_malloc_capture_4( | ||
| ; CHECK-NEXT: [[M:%.*]] = call i8* @malloc(i64 24) | ||
| ; CHECK-NEXT: store i8 0, i8* [[M]] | ||
| ; CHECK-NEXT: call void @may_throw_readnone() | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: store i8 1, i8* [[M]] | ||
| ; CHECK-NEXT: call void @capture(i8* [[M]]) | ||
| ; CHECK-NEXT: ret i8* [[M]] | ||
| ; | ||
|
|
||
| %m = call i8* @malloc(i64 24) | ||
| store i8 0, i8* %m | ||
| call void @may_throw_readnone() | ||
| br label %exit | ||
|
|
||
| exit: | ||
| store i8 1, i8* %m | ||
| call void @capture(i8* %m) | ||
| ret i8* %m | ||
| } | ||
|
|
||
|
|
||
| ; We cannot remove the first store store i8 0, i8* %m because %m escapes | ||
| ; before the killing store and we may throw in between. | ||
| define i8* @test_malloc_capture_5() { | ||
| ; CHECK-LABEL: @test_malloc_capture_5( | ||
| ; CHECK-NEXT: [[M:%.*]] = call i8* @malloc(i64 24) | ||
| ; CHECK-NEXT: call void @capture(i8* [[M]]) | ||
| ; CHECK-NEXT: store i8 0, i8* [[M]] | ||
| ; CHECK-NEXT: call void @may_throw_readnone() | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: store i8 1, i8* [[M]] | ||
| ; CHECK-NEXT: ret i8* [[M]] | ||
| ; | ||
|
|
||
| %m = call i8* @malloc(i64 24) | ||
| call void @capture(i8* %m) | ||
| store i8 0, i8* %m | ||
| call void @may_throw_readnone() | ||
| br label %exit | ||
|
|
||
| exit: | ||
| store i8 1, i8* %m | ||
| ret i8* %m | ||
| } | ||
|
|
||
|
|
||
| ; TODO: We could remove the first store 'store i8 0, i8* %m' even though there | ||
| ; is a throwing instruction between them, because %m escapes after the killing | ||
| ; store. | ||
| define i8* @test_malloc_capture_6() { | ||
| ; CHECK-LABEL: @test_malloc_capture_6( | ||
| ; CHECK-NEXT: [[M:%.*]] = call i8* @malloc(i64 24) | ||
| ; CHECK-NEXT: store i8 0, i8* [[M]] | ||
| ; CHECK-NEXT: call void @may_throw_readnone() | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: store i8 1, i8* [[M]] | ||
| ; CHECK-NEXT: call void @capture(i8* [[M]]) | ||
| ; CHECK-NEXT: ret i8* [[M]] | ||
| ; | ||
|
|
||
| %m = call i8* @malloc(i64 24) | ||
| store i8 0, i8* %m | ||
| call void @may_throw_readnone() | ||
| br label %exit | ||
|
|
||
| exit: | ||
| store i8 1, i8* %m | ||
| call void @capture(i8* %m) | ||
| ret i8* %m | ||
| } | ||
|
|
||
| ; We can remove the first store 'store i8 0, i8* %m' even though there is a | ||
| ; throwing instruction between them, because %m escapes after the killing store. | ||
| define i8* @test_malloc_capture_7() { | ||
| ; CHECK-LABEL: @test_malloc_capture_7( | ||
| ; CHECK-NEXT: [[M:%.*]] = call i8* @malloc(i64 24) | ||
| ; CHECK-NEXT: store i8 0, i8* [[M]] | ||
| ; CHECK-NEXT: call void @may_throw() | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: store i8 1, i8* [[M]] | ||
| ; CHECK-NEXT: call void @capture(i8* [[M]]) | ||
| ; CHECK-NEXT: ret i8* [[M]] | ||
| ; | ||
|
|
||
| %m = call i8* @malloc(i64 24) | ||
| store i8 0, i8* %m | ||
| call void @may_throw() | ||
| br label %exit | ||
|
|
||
| exit: | ||
| store i8 1, i8* %m | ||
| call void @capture(i8* %m) | ||
| ret i8* %m | ||
| } | ||
| ; TODO: Remove store in exit. | ||
| ; Stores to stack objects can be eliminated if they are not captured inside the function. | ||
| define void @test_alloca_nocapture_1() { | ||
| ; CHECK-LABEL: @test_alloca_nocapture_1( | ||
| ; CHECK-NEXT: [[M:%.*]] = alloca i8 | ||
| ; CHECK-NEXT: store i8 0, i8* [[M]] | ||
| ; CHECK-NEXT: call void @foo() | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %m = alloca i8 | ||
| store i8 0, i8* %m | ||
| call void @foo() | ||
| br label %exit | ||
|
|
||
| exit: | ||
| store i8 1, i8* %m | ||
| ret void | ||
| } | ||
|
|
||
| ; TODO: Remove store in exit. | ||
| ; Cannot remove first store i8 0, i8* %m, as the call to @capture captures the object. | ||
| define void @test_alloca_capture_1() { | ||
| ; CHECK-LABEL: @test_alloca_capture_1( | ||
| ; CHECK-NEXT: [[M:%.*]] = alloca i8 | ||
| ; CHECK-NEXT: store i8 0, i8* [[M]] | ||
| ; CHECK-NEXT: call void @capture(i8* [[M]]) | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %m = alloca i8 | ||
| store i8 0, i8* %m | ||
| call void @capture(i8* %m) | ||
| br label %exit | ||
|
|
||
| exit: | ||
| store i8 1, i8* %m | ||
| ret void | ||
| } | ||
|
|
||
| ; TODO: Remove store at exit. | ||
| ; We can remove the last store to %m, even though it escapes because the alloca | ||
| ; becomes invalid after the function returns. | ||
| define void @test_alloca_capture_2(%S1* %E) { | ||
| ; CHECK-LABEL: @test_alloca_capture_2( | ||
| ; CHECK-NEXT: [[M:%.*]] = alloca i8 | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: [[F_PTR:%.*]] = getelementptr [[S1:%.*]], %S1* [[E:%.*]], i32 0, i32 0 | ||
| ; CHECK-NEXT: store i8* [[M]], i8** [[F_PTR]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %m = alloca i8 | ||
| br label %exit | ||
|
|
||
| exit: | ||
| %f.ptr = getelementptr %S1, %S1* %E, i32 0, i32 0 | ||
| store i8* %m, i8** %f.ptr | ||
| store i8 1, i8* %m | ||
| ret void | ||
| } | ||
|
|
||
| ; Readnone functions are not modeled in MemorySSA, but could throw. | ||
| ; Make sure we do not eliminate the first store 'store i8 2, i8* %call' | ||
| define void @malloc_capture_throw_1() { | ||
| ; CHECK-LABEL: @malloc_capture_throw_1( | ||
| ; CHECK-NEXT: [[CALL:%.*]] = call i8* @malloc(i64 1) | ||
| ; CHECK-NEXT: call void @may_capture(i8* [[CALL]]) | ||
| ; CHECK-NEXT: store i8 2, i8* [[CALL]], align 1 | ||
| ; CHECK-NEXT: call void @may_throw_readnone() | ||
| ; CHECK-NEXT: store i8 3, i8* [[CALL]], align 1 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %call = call i8* @malloc(i64 1) | ||
| call void @may_capture(i8* %call) | ||
| store i8 2, i8* %call, align 1 | ||
| call void @may_throw_readnone() | ||
| store i8 3, i8* %call, align 1 | ||
| ret void | ||
| } | ||
|
|
||
| ; Readnone functions are not modeled in MemorySSA, but could throw. | ||
| ; Make sure we do not eliminate the first store 'store i8 2, i8* %call' | ||
| define void @malloc_capture_throw_2() { | ||
| ; CHECK-LABEL: @malloc_capture_throw_2( | ||
| ; CHECK-NEXT: [[CALL:%.*]] = call i8* @malloc(i64 1) | ||
| ; CHECK-NEXT: call void @may_capture(i8* [[CALL]]) | ||
| ; CHECK-NEXT: store i8 2, i8* [[CALL]], align 1 | ||
| ; CHECK-NEXT: br label [[BB:%.*]] | ||
| ; CHECK: bb: | ||
| ; CHECK-NEXT: call void @may_throw_readnone() | ||
| ; CHECK-NEXT: store i8 3, i8* [[CALL]], align 1 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %call = call i8* @malloc(i64 1) | ||
| call void @may_capture(i8* %call) | ||
| store i8 2, i8* %call, align 1 | ||
| br label %bb | ||
|
|
||
| bb: | ||
| call void @may_throw_readnone() | ||
| store i8 3, i8* %call, align 1 | ||
| ret void | ||
| } | ||
|
|
||
|
|
||
| declare void @may_capture(i8*) | ||
| declare void @may_throw_readnone() readnone | ||
| declare void @may_throw() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s | ||
| target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" | ||
|
|
||
| declare void @f() | ||
| declare i32 @__CxxFrameHandler3(...) | ||
|
|
||
|
|
||
| ; Make sure we do not eliminate `store i32 20, i32* %sv`. Even though it is a store | ||
| ; to a stack object, we can read it in the landing/catchpad. | ||
| define void @test12(i32* %p) personality i32 (...)* @__CxxFrameHandler3 { | ||
| ; CHECK-LABEL: @test12( | ||
| ; CHECK-NEXT: block1: | ||
| ; CHECK-NEXT: [[SV:%.*]] = alloca i32 | ||
| ; CHECK-NEXT: br label [[BLOCK2:%.*]] | ||
| ; CHECK: block2: | ||
| ; CHECK-NEXT: store i32 20, i32* [[SV]] | ||
| ; CHECK-NEXT: invoke void @f() | ||
| ; CHECK-NEXT: to label [[BLOCK3:%.*]] unwind label [[CATCH_DISPATCH:%.*]] | ||
| ; CHECK: block3: | ||
| ; CHECK-NEXT: store i32 30, i32* [[SV]] | ||
| ; CHECK-NEXT: br label [[EXIT:%.*]] | ||
| ; CHECK: catch.dispatch: | ||
| ; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catch] unwind label [[CLEANUP:%.*]] | ||
| ; CHECK: catch: | ||
| ; CHECK-NEXT: [[C:%.*]] = catchpad within [[CS1]] [] | ||
| ; CHECK-NEXT: [[LV:%.*]] = load i32, i32* [[SV]] | ||
| ; CHECK-NEXT: br label [[EXIT]] | ||
| ; CHECK: cleanup: | ||
| ; CHECK-NEXT: [[C1:%.*]] = cleanuppad within none [] | ||
| ; CHECK-NEXT: br label [[EXIT]] | ||
| ; CHECK: exit: | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| block1: | ||
| %sv = alloca i32 | ||
| br label %block2 | ||
|
|
||
| block2: | ||
| store i32 20, i32* %sv | ||
| invoke void @f() | ||
| to label %block3 unwind label %catch.dispatch | ||
|
|
||
| block3: | ||
| store i32 30, i32* %sv | ||
| br label %exit | ||
|
|
||
| catch.dispatch: | ||
| %cs1 = catchswitch within none [label %catch] unwind label %cleanup | ||
|
|
||
| catch: | ||
| %c = catchpad within %cs1 [] | ||
| %lv = load i32, i32* %sv | ||
| br label %exit | ||
|
|
||
| cleanup: | ||
| %c1 = cleanuppad within none [] | ||
| br label %exit | ||
|
|
||
| exit: | ||
| store i32 40, i32* %sv | ||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s | ||
|
|
||
| target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" | ||
| declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind | ||
|
|
||
| define void @test13(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test13( | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: br label [[FOR:%.*]] | ||
| ; CHECK: for: | ||
| ; CHECK-NEXT: store i32 0, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br i1 false, label [[FOR]], label [[END:%.*]] | ||
| ; CHECK: end: | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| entry: | ||
| br label %for | ||
| for: | ||
| store i32 0, i32* %P | ||
| br i1 false, label %for, label %end | ||
| end: | ||
| ret void | ||
| } | ||
|
|
||
|
|
||
| define void @test14(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test14( | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: store i32 1, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br label [[FOR:%.*]] | ||
| ; CHECK: for: | ||
| ; CHECK-NEXT: store i32 0, i32* [[P]] | ||
| ; CHECK-NEXT: br i1 false, label [[FOR]], label [[END:%.*]] | ||
| ; CHECK: end: | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| entry: | ||
| store i32 1, i32* %P | ||
| br label %for | ||
| for: | ||
| store i32 0, i32* %P | ||
| br i1 false, label %for, label %end | ||
| end: | ||
| ret void | ||
| } | ||
|
|
||
| define void @test18(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test18( | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P:%.*]] to i8* | ||
| ; CHECK-NEXT: store i32 0, i32* [[P]] | ||
| ; CHECK-NEXT: br label [[FOR:%.*]] | ||
| ; CHECK: for: | ||
| ; CHECK-NEXT: store i8 1, i8* [[P2]] | ||
| ; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P]] | ||
| ; CHECK-NEXT: store i8 2, i8* [[P2]] | ||
| ; CHECK-NEXT: br i1 false, label [[FOR]], label [[END:%.*]] | ||
| ; CHECK: end: | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| entry: | ||
| %P2 = bitcast i32* %P to i8* | ||
| store i32 0, i32* %P | ||
| br label %for | ||
| for: | ||
| store i8 1, i8* %P2 | ||
| %x = load i32, i32* %P | ||
| store i8 2, i8* %P2 | ||
| br i1 false, label %for, label %end | ||
| end: | ||
| ret void | ||
| } | ||
|
|
||
| define void @test21(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test21( | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 | ||
| ; CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[ARRAYIDX0]] to i8* | ||
| ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[P3]], i8 0, i64 28, i1 false) | ||
| ; CHECK-NEXT: br label [[FOR:%.*]] | ||
| ; CHECK: for: | ||
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 1 | ||
| ; CHECK-NEXT: store i32 1, i32* [[ARRAYIDX1]], align 4 | ||
| ; CHECK-NEXT: br i1 false, label [[FOR]], label [[END:%.*]] | ||
| ; CHECK: end: | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| entry: | ||
| %arrayidx0 = getelementptr inbounds i32, i32* %P, i64 1 | ||
| %p3 = bitcast i32* %arrayidx0 to i8* | ||
| call void @llvm.memset.p0i8.i64(i8* %p3, i8 0, i64 28, i32 4, i1 false) | ||
| br label %for | ||
| for: | ||
| %arrayidx1 = getelementptr inbounds i32, i32* %P, i64 1 | ||
| store i32 1, i32* %arrayidx1, align 4 | ||
| br i1 false, label %for, label %end | ||
| end: | ||
| ret void | ||
| } | ||
|
|
||
| define void @test_loop(i32 %N, i32* noalias nocapture readonly %A, i32* noalias nocapture readonly %x, i32* noalias nocapture %b) local_unnamed_addr { | ||
| ; CHECK-LABEL: @test_loop( | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: [[CMP27:%.*]] = icmp sgt i32 [[N:%.*]], 0 | ||
| ; CHECK-NEXT: br i1 [[CMP27]], label [[FOR_BODY4_LR_PH_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]] | ||
| ; CHECK: for.body4.lr.ph.preheader: | ||
| ; CHECK-NEXT: br label [[FOR_BODY4_LR_PH:%.*]] | ||
| ; CHECK: for.cond.cleanup: | ||
| ; CHECK-NEXT: ret void | ||
| ; CHECK: for.body4.lr.ph: | ||
| ; CHECK-NEXT: [[I_028:%.*]] = phi i32 [ [[INC11:%.*]], [[FOR_COND_CLEANUP3:%.*]] ], [ 0, [[FOR_BODY4_LR_PH_PREHEADER]] ] | ||
| ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[B:%.*]], i32 [[I_028]] | ||
| ; CHECK-NEXT: store i32 0, i32* [[ARRAYIDX]], align 4 | ||
| ; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[I_028]], [[N]] | ||
| ; CHECK-NEXT: br label [[FOR_BODY4:%.*]] | ||
| ; CHECK: for.body4: | ||
| ; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 0, [[FOR_BODY4_LR_PH]] ], [ [[ADD9:%.*]], [[FOR_BODY4]] ] | ||
| ; CHECK-NEXT: [[J_026:%.*]] = phi i32 [ 0, [[FOR_BODY4_LR_PH]] ], [ [[INC:%.*]], [[FOR_BODY4]] ] | ||
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[J_026]], [[MUL]] | ||
| ; CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds i32, i32* [[A:%.*]], i32 [[ADD]] | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[ARRAYIDX5]], align 4 | ||
| ; CHECK-NEXT: [[ARRAYIDX6:%.*]] = getelementptr inbounds i32, i32* [[X:%.*]], i32 [[J_026]] | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[ARRAYIDX6]], align 4 | ||
| ; CHECK-NEXT: [[MUL7:%.*]] = mul nsw i32 [[TMP2]], [[TMP1]] | ||
| ; CHECK-NEXT: [[ADD9]] = add nsw i32 [[MUL7]], [[TMP0]] | ||
| ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[J_026]], 1 | ||
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], [[N]] | ||
| ; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP3]], label [[FOR_BODY4]] | ||
| ; CHECK: for.cond.cleanup3: | ||
| ; CHECK-NEXT: store i32 [[ADD9]], i32* [[ARRAYIDX]], align 4 | ||
| ; CHECK-NEXT: [[INC11]] = add nuw nsw i32 [[I_028]], 1 | ||
| ; CHECK-NEXT: [[EXITCOND29:%.*]] = icmp eq i32 [[INC11]], [[N]] | ||
| ; CHECK-NEXT: br i1 [[EXITCOND29]], label [[FOR_COND_CLEANUP]], label [[FOR_BODY4_LR_PH]] | ||
| ; | ||
| entry: | ||
| %cmp27 = icmp sgt i32 %N, 0 | ||
| br i1 %cmp27, label %for.body4.lr.ph.preheader, label %for.cond.cleanup | ||
|
|
||
| for.body4.lr.ph.preheader: ; preds = %entry | ||
| br label %for.body4.lr.ph | ||
|
|
||
| for.cond.cleanup: ; preds = %for.cond.cleanup3, %entry | ||
| ret void | ||
|
|
||
| for.body4.lr.ph: ; preds = %for.body4.lr.ph.preheader, %for.cond.cleanup3 | ||
| %i.028 = phi i32 [ %inc11, %for.cond.cleanup3 ], [ 0, %for.body4.lr.ph.preheader ] | ||
| %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.028 | ||
| store i32 0, i32* %arrayidx, align 4 | ||
| %mul = mul nsw i32 %i.028, %N | ||
| br label %for.body4 | ||
|
|
||
| for.body4: ; preds = %for.body4, %for.body4.lr.ph | ||
| %0 = phi i32 [ 0, %for.body4.lr.ph ], [ %add9, %for.body4 ] | ||
| %j.026 = phi i32 [ 0, %for.body4.lr.ph ], [ %inc, %for.body4 ] | ||
| %add = add nsw i32 %j.026, %mul | ||
| %arrayidx5 = getelementptr inbounds i32, i32* %A, i32 %add | ||
| %1 = load i32, i32* %arrayidx5, align 4 | ||
| %arrayidx6 = getelementptr inbounds i32, i32* %x, i32 %j.026 | ||
| %2 = load i32, i32* %arrayidx6, align 4 | ||
| %mul7 = mul nsw i32 %2, %1 | ||
| %add9 = add nsw i32 %mul7, %0 | ||
| %inc = add nuw nsw i32 %j.026, 1 | ||
| %exitcond = icmp eq i32 %inc, %N | ||
| br i1 %exitcond, label %for.cond.cleanup3, label %for.body4 | ||
|
|
||
| for.cond.cleanup3: ; preds = %for.body4 | ||
| store i32 %add9, i32* %arrayidx, align 4 | ||
| %inc11 = add nuw nsw i32 %i.028, 1 | ||
| %exitcond29 = icmp eq i32 %inc11, %N | ||
| br i1 %exitcond29, label %for.cond.cleanup, label %for.body4.lr.ph | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s | ||
|
|
||
| target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" | ||
| declare void @unknown_func() | ||
| declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) nounwind | ||
| declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind | ||
|
|
||
| define void @test19(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test19( | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 | ||
| ; CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[ARRAYIDX0]] to i8* | ||
| ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[P3]], i8 0, i64 28, i1 false) | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 1 | ||
| ; CHECK-NEXT: store i32 1, i32* [[ARRAYIDX1]], align 4 | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| entry: | ||
| %arrayidx0 = getelementptr inbounds i32, i32* %P, i64 1 | ||
| %p3 = bitcast i32* %arrayidx0 to i8* | ||
| call void @llvm.memset.p0i8.i64(i8* %p3, i8 0, i64 28, i32 4, i1 false) | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| br label %bb3 | ||
| bb2: | ||
| %arrayidx1 = getelementptr inbounds i32, i32* %P, i64 1 | ||
| store i32 1, i32* %arrayidx1, align 4 | ||
| br label %bb3 | ||
| bb3: | ||
| ret void | ||
| } | ||
|
|
||
|
|
||
| define void @test20(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test20( | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 | ||
| ; CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[ARRAYIDX0]] to i8* | ||
| ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[P3]], i8 0, i64 28, i1 false) | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 1 | ||
| ; CHECK-NEXT: store i32 1, i32* [[ARRAYIDX1]], align 4 | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| entry: | ||
| %arrayidx0 = getelementptr inbounds i32, i32* %P, i64 1 | ||
| %p3 = bitcast i32* %arrayidx0 to i8* | ||
| call void @llvm.memset.p0i8.i64(i8* %p3, i8 0, i64 28, i32 4, i1 false) | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| br label %bb3 | ||
| bb2: | ||
| br label %bb3 | ||
| bb3: | ||
| %arrayidx1 = getelementptr inbounds i32, i32* %P, i64 1 | ||
| store i32 1, i32* %arrayidx1, align 4 | ||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s | ||
|
|
||
| target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" | ||
|
|
||
|
|
||
| define void @test4(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test4( | ||
| ; CHECK-NEXT: store i32 0, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P]] | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: store i32 0, i32* [[P]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| store i32 0, i32* %P | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| br label %bb3 | ||
| bb2: | ||
| %x = load i32, i32* %P | ||
| br label %bb3 | ||
| bb3: | ||
| store i32 0, i32* %P | ||
| ret void | ||
| } | ||
|
|
||
| define void @test5(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test5( | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: store i32 1, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: store i32 1, i32* [[P]] | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: store i32 0, i32* [[P]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| store i32 1, i32* %P | ||
| br label %bb3 | ||
| bb2: | ||
| store i32 1, i32* %P | ||
| br label %bb3 | ||
| bb3: | ||
| store i32 0, i32* %P | ||
| ret void | ||
| } | ||
|
|
||
| define void @test8(i32* %P, i32* %Q) { | ||
| ; CHECK-LABEL: @test8( | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: store i32 1, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: store i32 1, i32* [[Q:%.*]] | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: store i32 0, i32* [[P]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| store i32 1, i32* %P | ||
| br label %bb3 | ||
| bb2: | ||
| store i32 1, i32* %Q | ||
| br label %bb3 | ||
| bb3: | ||
| store i32 0, i32* %P | ||
| ret void | ||
| } | ||
|
|
||
| define void @test10(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test10( | ||
| ; CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P:%.*]] to i8* | ||
| ; CHECK-NEXT: store i32 0, i32* [[P]] | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: store i8 1, i8* [[P2]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %P2 = bitcast i32* %P to i8* | ||
| store i32 0, i32* %P | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| br label %bb3 | ||
| bb2: | ||
| br label %bb3 | ||
| bb3: | ||
| store i8 1, i8* %P2 | ||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s | ||
|
|
||
| target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" | ||
|
|
||
|
|
||
| define void @second_store_smaller(i32* noalias %P) { | ||
| ; CHECK-LABEL: @second_store_smaller( | ||
| ; CHECK-NEXT: store i32 1, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: [[P_I16:%.*]] = bitcast i32* [[P]] to i16* | ||
| ; CHECK-NEXT: store i16 0, i16* [[P_I16]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| store i32 1, i32* %P | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| br label %bb3 | ||
| bb2: | ||
| br label %bb3 | ||
| bb3: | ||
| %P.i16 = bitcast i32* %P to i16* | ||
| store i16 0, i16* %P.i16 | ||
| ret void | ||
| } | ||
|
|
||
|
|
||
| define void @second_store_bigger(i32* noalias %P) { | ||
| ; CHECK-LABEL: @second_store_bigger( | ||
| ; CHECK-NEXT: store i32 1, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: [[P_I64:%.*]] = bitcast i32* [[P]] to i64* | ||
| ; CHECK-NEXT: store i64 0, i64* [[P_I64]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| store i32 1, i32* %P | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| br label %bb3 | ||
| bb2: | ||
| br label %bb3 | ||
| bb3: | ||
| %P.i64 = bitcast i32* %P to i64* | ||
| store i64 0, i64* %P.i64 | ||
| ret void | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s | ||
|
|
||
| target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" | ||
|
|
||
|
|
||
| define void @test2(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test2( | ||
| ; CHECK-NEXT: store i32 1, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: store i32 0, i32* [[P]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| store i32 1, i32* %P | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| br label %bb3 | ||
| bb2: | ||
| br label %bb3 | ||
| bb3: | ||
| store i32 0, i32* %P | ||
| ret void | ||
| } | ||
|
|
||
| define void @test3(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test3( | ||
| ; CHECK-NEXT: store i32 0, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: store i32 0, i32* [[P]] | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| store i32 0, i32* %P | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| br label %bb3 | ||
| bb2: | ||
| store i32 0, i32* %P | ||
| br label %bb3 | ||
| bb3: | ||
| ret void | ||
| } | ||
|
|
||
|
|
||
| define void @test7(i32* noalias %P, i32* noalias %Q) { | ||
| ; CHECK-LABEL: @test7( | ||
| ; CHECK-NEXT: store i32 1, i32* [[Q:%.*]] | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: store i32 0, i32* [[Q]] | ||
| ; CHECK-NEXT: store i32 0, i32* [[P]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| store i32 1, i32* %Q | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| load i32, i32* %P | ||
| br label %bb3 | ||
| bb2: | ||
| br label %bb3 | ||
| bb3: | ||
| store i32 0, i32* %Q | ||
| store i32 0, i32* %P | ||
| ret void | ||
| } | ||
|
|
||
| define i32 @test22(i32* %P, i32* noalias %Q, i32* %R) { | ||
| ; CHECK-LABEL: @test22( | ||
| ; CHECK-NEXT: store i32 2, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: store i32 3, i32* [[Q:%.*]] | ||
| ; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[R:%.*]] | ||
| ; CHECK-NEXT: ret i32 [[L]] | ||
| ; | ||
| store i32 1, i32* %Q | ||
| store i32 2, i32* %P | ||
| store i32 3, i32* %Q | ||
| %l = load i32, i32* %R | ||
| ret i32 %l | ||
| } | ||
|
|
||
| define void @test9(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test9( | ||
| ; CHECK-NEXT: store i32 0, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: ret void | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: store i32 0, i32* [[P]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| store i32 0, i32* %P | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| br label %bb3 | ||
| bb2: | ||
| ret void | ||
| bb3: | ||
| store i32 0, i32* %P | ||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; XFAIL: * | ||
| ; RUN: opt < %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s | ||
|
|
||
| target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" | ||
| declare void @unknown_func() | ||
|
|
||
| define void @test6(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test6( | ||
| ; CHECK-NEXT: store i32 0, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: call void @unknown_func() | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: store i32 0, i32* [[P]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| store i32 0, i32* %P | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| br label %bb3 | ||
| bb2: | ||
| call void @unknown_func() | ||
| br label %bb3 | ||
| bb3: | ||
| store i32 0, i32* %P | ||
| ret void | ||
| } | ||
|
|
||
| define i32 @test22(i32* %P, i32* noalias %Q, i32* %R) { | ||
| ; CHECK-LABEL: @test22( | ||
| ; CHECK-NEXT: store i32 2, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: store i32 3, i32* [[Q:%.*]] | ||
| ; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[R:%.*]] | ||
| ; CHECK-NEXT: ret i32 [[L]] | ||
| ; | ||
| store i32 1, i32* %Q | ||
| store i32 2, i32* %P | ||
| store i32 3, i32* %Q | ||
| %l = load i32, i32* %R | ||
| ret i32 %l | ||
| } | ||
|
|
||
|
|
||
| define void @test23(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test23( | ||
| ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: call void @unknown_func() | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: store i32 0, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| br i1 true, label %bb1, label %bb2 | ||
| bb1: | ||
| store i32 0, i32* %P | ||
| br label %bb3 | ||
| bb2: | ||
| call void @unknown_func() | ||
| br label %bb3 | ||
| bb3: | ||
| store i32 0, i32* %P | ||
| ret void | ||
| } | ||
|
|
||
|
|
||
| define void @test24(i32* noalias %P) { | ||
| ; CHECK-LABEL: @test24( | ||
| ; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[BB1:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: br label [[BB3:%.*]] | ||
| ; CHECK: bb2: | ||
| ; CHECK-NEXT: call void @unknown_func() | ||
| ; CHECK-NEXT: br label [[BB3]] | ||
| ; CHECK: bb3: | ||
| ; CHECK-NEXT: store i32 0, i32* [[P:%.*]] | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| br i1 true, label %bb2, label %bb1 | ||
| bb1: | ||
| store i32 0, i32* %P | ||
| br label %bb3 | ||
| bb2: | ||
| call void @unknown_func() | ||
| br label %bb3 | ||
| bb3: | ||
| store i32 0, i32* %P | ||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| ; RUN: opt -basicaa -dse -enable-dse-memoryssa -S < %s | FileCheck %s | ||
|
|
||
| declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) nounwind | ||
|
|
||
| define void @fn(i8* nocapture %buf) #0 { | ||
| entry: | ||
|
|
||
| ; We would not eliminate the first memcpy with data layout, and we should not | ||
| ; eliminate it without data layout. | ||
| ; CHECK-LABEL: @fn | ||
| ; CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64 | ||
| ; CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64 | ||
| ; CHECK: ret void | ||
|
|
||
| %arrayidx = getelementptr i8, i8* %buf, i64 18 | ||
| tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %arrayidx, i8* %buf, i64 18, i1 false) | ||
| store i8 1, i8* %arrayidx, align 1 | ||
| tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %buf, i8* %arrayidx, i64 18, i1 false) | ||
| ret void | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| ; RUN: opt < %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s | ||
|
|
||
| declare noalias i8* @malloc(i64) "malloc-like" | ||
|
|
||
| declare void @foo() | ||
| declare void @bar(i8*) | ||
|
|
||
| define void @test() { | ||
| %obj = call i8* @malloc(i64 8) | ||
| store i8 0, i8* %obj | ||
| ; don't remove store. %obj should be treated like it will be read by the @foo. | ||
| ; CHECK: store i8 0, i8* %obj | ||
| call void @foo() ["deopt" (i8* %obj)] | ||
| ret void | ||
| } | ||
|
|
||
| define void @test1() { | ||
| %obj = call i8* @malloc(i64 8) | ||
| store i8 0, i8* %obj | ||
| ; CHECK: store i8 0, i8* %obj | ||
| call void @bar(i8* nocapture %obj) | ||
| ret void | ||
| } | ||
|
|
||
| define void @test2() { | ||
| %obj = call i8* @malloc(i64 8) | ||
| store i8 0, i8* %obj | ||
| ; CHECK-NOT: store i8 0, i8* %obj | ||
| call void @foo() | ||
| ret void | ||
| } | ||
|
|
||
| define void @test3() { | ||
| ; CHECK-LABEL: @test3( | ||
| %s = alloca i64 | ||
| ; Verify that this first store is not considered killed by the second one | ||
| ; since it could be observed from the deopt continuation. | ||
| ; CHECK: store i64 1, i64* %s | ||
| store i64 1, i64* %s | ||
| call void @foo() [ "deopt"(i64* %s) ] | ||
| store i64 0, i64* %s | ||
| ret void | ||
| } | ||
|
|
||
| declare noalias i8* @calloc(i64, i64) | ||
|
|
||
| define void @test4() { | ||
| ; CHECK-LABEL: @test4 | ||
| %local_obj = call i8* @calloc(i64 1, i64 4) | ||
| call void @foo() ["deopt" (i8* %local_obj)] | ||
| store i8 0, i8* %local_obj, align 4 | ||
| ; CHECK-NOT: store i8 0, i8* %local_obj, align 4 | ||
| call void @bar(i8* nocapture %local_obj) | ||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
| ; RUN: opt < %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s | ||
| ; RUN: opt < %s -aa-pipeline=basic-aa -passes=dse -enable-dse-memoryssa -S | FileCheck %s | ||
|
|
||
| declare void @use(i64*) | ||
|
|
||
| define void @test1() { | ||
| ; CHECK-LABEL: @test1( | ||
| ; CHECK-NEXT: [[A:%.*]] = alloca i64 | ||
| ; CHECK-NEXT: call void @use(i64* [[A]]) | ||
| ; CHECK-NEXT: [[PTR1:%.*]] = bitcast i64* [[A]] to i8* | ||
| ; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, i8* [[PTR1]], i32 1 | ||
| ; CHECK-NEXT: store i8 10, i8* [[PTR1]] | ||
| ; CHECK-NEXT: store i8 20, i8* [[PTR2]] | ||
| ; CHECK-NEXT: [[LV:%.*]] = load i64, i64* [[A]] | ||
| ; CHECK-NEXT: store i8 0, i8* [[PTR1]] | ||
| ; CHECK-NEXT: call void @use(i64* [[A]]) | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %a = alloca i64 | ||
| call void @use(i64* %a) | ||
| %ptr1 = bitcast i64* %a to i8* | ||
| %ptr2 = getelementptr i8, i8* %ptr1, i32 1 | ||
|
|
||
| store i8 10, i8* %ptr1 | ||
| store i8 20, i8* %ptr2 | ||
| %lv = load i64, i64* %a | ||
| store i8 0, i8* %ptr1 | ||
|
|
||
| call void @use(i64* %a) | ||
| ret void | ||
| } | ||
|
|
||
| define void @test2() { | ||
| ; CHECK-LABEL: @test2( | ||
| ; CHECK-NEXT: [[A:%.*]] = alloca i64 | ||
| ; CHECK-NEXT: call void @use(i64* [[A]]) | ||
| ; CHECK-NEXT: [[PTR1:%.*]] = bitcast i64* [[A]] to i8* | ||
| ; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i8, i8* [[PTR1]], i32 1 | ||
| ; CHECK-NEXT: store i8 10, i8* [[PTR1]] | ||
| ; CHECK-NEXT: store i8 20, i8* [[PTR2]] | ||
| ; CHECK-NEXT: br i1 undef, label [[BB1:%.*]], label [[END:%.*]] | ||
| ; CHECK: bb1: | ||
| ; CHECK-NEXT: [[LV:%.*]] = load i64, i64* [[A]] | ||
| ; CHECK-NEXT: br label [[END]] | ||
| ; CHECK: end: | ||
| ; CHECK-NEXT: store i8 0, i8* [[PTR1]] | ||
| ; CHECK-NEXT: call void @use(i64* [[A]]) | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| %a = alloca i64 | ||
| call void @use(i64* %a) | ||
| %ptr1 = bitcast i64* %a to i8* | ||
| %ptr2 = getelementptr i8, i8* %ptr1, i32 1 | ||
|
|
||
| store i8 10, i8* %ptr1 | ||
| store i8 20, i8* %ptr2 | ||
| br i1 undef, label %bb1, label %end | ||
|
|
||
| bb1: | ||
| %lv = load i64, i64* %a | ||
| br label %end | ||
|
|
||
| end: | ||
| store i8 0, i8* %ptr1 | ||
| call void @use(i64* %a) | ||
| ret void | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| ; RUN: opt -basicaa -dse -enable-dse-memoryssa -S < %s | FileCheck %s | ||
| ; PR11390 | ||
| target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" | ||
| target triple = "x86_64-unknown-linux-gnu" | ||
|
|
||
| define fastcc void @cat_domain(i8* nocapture %name, i8* nocapture %domain, i8** | ||
| nocapture %s) nounwind uwtable { | ||
| entry: | ||
| %call = tail call i64 @strlen(i8* %name) nounwind readonly | ||
| %call1 = tail call i64 @strlen(i8* %domain) nounwind readonly | ||
| %add = add i64 %call, 1 | ||
| %add2 = add i64 %add, %call1 | ||
| %add3 = add i64 %add2, 1 | ||
| %call4 = tail call noalias i8* @malloc(i64 %add3) nounwind | ||
| store i8* %call4, i8** %s, align 8 | ||
| %tobool = icmp eq i8* %call4, null | ||
| br i1 %tobool, label %return, label %if.end | ||
|
|
||
| if.end: ; preds = %entry | ||
| tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %call4, i8* %name, i64 %call, i1 false) | ||
| %arrayidx = getelementptr inbounds i8, i8* %call4, i64 %call | ||
| store i8 46, i8* %arrayidx, align 1 | ||
| ; CHECK: store i8 46 | ||
| %add.ptr5 = getelementptr inbounds i8, i8* %call4, i64 %add | ||
| tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %add.ptr5, i8* %domain, i64 %call1, i1 false) | ||
| %arrayidx8 = getelementptr inbounds i8, i8* %call4, i64 %add2 | ||
| store i8 0, i8* %arrayidx8, align 1 | ||
| br label %return | ||
|
|
||
| return: ; preds = %if.end, %entry | ||
| ret void | ||
| } | ||
|
|
||
| declare i64 @strlen(i8* nocapture) nounwind readonly | ||
|
|
||
| declare noalias i8* @malloc(i64) nounwind | ||
|
|
||
| declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) nounwind |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| ; RUN: opt -dse -enable-dse-memoryssa -S < %s | FileCheck %s | ||
|
|
||
| ; Don't eliminate stores to allocas before tail calls to functions that use | ||
| ; byval. It's correct to mark calls like these as 'tail'. To implement this tail | ||
| ; call, the backend should copy the bytes from the alloca into the argument area | ||
| ; before clearing the stack. | ||
|
|
||
| target datalayout = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128" | ||
| target triple = "i386-unknown-linux-gnu" | ||
|
|
||
| declare void @g(i32* byval %p) | ||
|
|
||
| define void @f(i32* byval %x) { | ||
| entry: | ||
| %p = alloca i32 | ||
| %v = load i32, i32* %x | ||
| store i32 %v, i32* %p | ||
| tail call void @g(i32* byval %p) | ||
| ret void | ||
| } | ||
| ; CHECK-LABEL: define void @f(i32* byval %x) | ||
| ; CHECK: store i32 %v, i32* %p | ||
| ; CHECK: tail call void @g(i32* byval %p) |