| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -basic-aa -dse -S | FileCheck %s |
| |
| target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" |
| |
| declare void @readnone_may_throw() readnone |
| |
| declare void @use(i32 *) |
| |
| ; Tests where the pointer/object is accessible after the function returns. |
| |
| ; Cannot remove the store from the entry block, because the call in bb2 may throw. |
| define void @accessible_after_return_1(i32* noalias %P, i1 %c1) { |
| ; CHECK-LABEL: @accessible_after_return_1( |
| ; CHECK-NEXT: store i32 1, i32* [[P:%.*]], align 4 |
| ; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: store i32 0, i32* [[P]], align 4 |
| ; CHECK-NEXT: br label [[BB5:%.*]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: call void @readnone_may_throw() |
| ; CHECK-NEXT: store i32 3, i32* [[P]], align 4 |
| ; CHECK-NEXT: br label [[BB5]] |
| ; CHECK: bb5: |
| ; CHECK-NEXT: call void @use(i32* [[P]]) |
| ; CHECK-NEXT: ret void |
| ; |
| store i32 1, i32* %P |
| br i1 %c1, label %bb1, label %bb2 |
| |
| bb1: |
| store i32 0, i32* %P |
| br label %bb5 |
| |
| bb2: |
| call void @readnone_may_throw() |
| store i32 3, i32* %P |
| br label %bb5 |
| |
| bb5: |
| call void @use(i32* %P) |
| ret void |
| } |
| |
| ; Cannot remove the store from the entry block, because the call in bb3 may throw. |
| define void @accessible_after_return6(i32* %P, i1 %c.1, i1 %c.2) { |
| ; CHECK-LABEL: @accessible_after_return6( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: store i32 0, i32* [[P:%.*]], align 4 |
| ; CHECK-NEXT: br i1 [[C_1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: br i1 [[C_2:%.*]], label [[BB3:%.*]], label [[BB4:%.*]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: store i32 1, i32* [[P]], align 4 |
| ; CHECK-NEXT: ret void |
| ; CHECK: bb3: |
| ; CHECK-NEXT: call void @readnone_may_throw() |
| ; CHECK-NEXT: store i32 2, i32* [[P]], align 4 |
| ; CHECK-NEXT: ret void |
| ; CHECK: bb4: |
| ; CHECK-NEXT: store i32 3, i32* [[P]], align 4 |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| store i32 0, i32* %P |
| br i1 %c.1, label %bb1, label %bb2 |
| |
| bb1: |
| br i1 %c.2, label %bb3, label %bb4 |
| |
| bb2: |
| store i32 1, i32* %P |
| ret void |
| |
| bb3: |
| call void @readnone_may_throw() |
| store i32 2, i32* %P |
| ret void |
| |
| bb4: |
| store i32 3, i32* %P |
| ret void |
| } |
| |
| ; Tests where the pointer/object is *NOT* accessible after the function returns. |
| |
| ; The store in the entry block can be eliminated, because it is overwritten |
| ; on all paths to the exit. As the location is not visible to the caller, the |
| ; call in bb2 (which may throw) can be ignored. |
| define void @alloca_1(i1 %c1) { |
| ; CHECK-LABEL: @alloca_1( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[P:%.*]] = alloca i32 |
| ; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: store i32 0, i32* [[P]], align 4 |
| ; CHECK-NEXT: br label [[BB5:%.*]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: call void @readnone_may_throw() |
| ; CHECK-NEXT: store i32 3, i32* [[P]], align 4 |
| ; CHECK-NEXT: br label [[BB5]] |
| ; CHECK: bb5: |
| ; CHECK-NEXT: call void @use(i32* [[P]]) |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %P = alloca i32 |
| store i32 1, i32* %P |
| br i1 %c1, label %bb1, label %bb2 |
| |
| bb1: |
| store i32 0, i32* %P |
| br label %bb5 |
| |
| bb2: |
| call void @readnone_may_throw() |
| store i32 3, i32* %P |
| br label %bb5 |
| |
| bb5: |
| call void @use(i32* %P) |
| ret void |
| } |
| |
| ; The store in the entry block can be eliminated, because it is overwritten |
| ; on all paths to the exit. As the location is not visible to the caller, the |
| ; call in bb3 (which may throw) can be ignored. |
| define void @alloca_2(i1 %c.1, i1 %c.2) { |
| ; CHECK-LABEL: @alloca_2( |
| ; CHECK-NEXT: [[P:%.*]] = alloca i32 |
| ; CHECK-NEXT: br i1 [[C_1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: store i32 0, i32* [[P]], align 4 |
| ; CHECK-NEXT: br label [[BB5:%.*]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: br i1 [[C_2:%.*]], label [[BB3:%.*]], label [[BB4:%.*]] |
| ; CHECK: bb3: |
| ; CHECK-NEXT: call void @readnone_may_throw() |
| ; CHECK-NEXT: store i32 3, i32* [[P]], align 4 |
| ; CHECK-NEXT: br label [[BB5]] |
| ; CHECK: bb4: |
| ; CHECK-NEXT: store i32 5, i32* [[P]], align 4 |
| ; CHECK-NEXT: br label [[BB5]] |
| ; CHECK: bb5: |
| ; CHECK-NEXT: call void @use(i32* [[P]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %P = alloca i32 |
| store i32 1, i32* %P |
| br i1 %c.1, label %bb1, label %bb2 |
| |
| bb1: |
| store i32 0, i32* %P |
| br label %bb5 |
| |
| bb2: |
| br i1 %c.2, label %bb3, label %bb4 |
| |
| bb3: |
| call void @readnone_may_throw() |
| store i32 3, i32* %P |
| br label %bb5 |
| |
| bb4: |
| store i32 5, i32* %P |
| br label %bb5 |
| |
| bb5: |
| call void @use(i32* %P) |
| ret void |
| } |