| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -S -passes=dse < %s | FileCheck %s |
| |
| target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" |
| |
| declare void @llvm.lifetime.start.p0(i64, ptr nocapture) nounwind |
| declare void @llvm.lifetime.end.p0(i64, ptr nocapture) nounwind |
| declare void @llvm.memset.p0.i8(ptr nocapture, i8, i8, i1) nounwind |
| |
| define void @test1() { |
| ; CHECK-LABEL: @test1( |
| ; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 |
| ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[A]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %A = alloca i8 |
| |
| store i8 0, ptr %A ;; Written to by memset |
| call void @llvm.lifetime.end.p0(i64 1, ptr %A) |
| |
| call void @llvm.memset.p0.i8(ptr %A, i8 0, i8 -1, i1 false) |
| |
| ret void |
| } |
| |
| define void @test2(ptr %P) { |
| ; CHECK-LABEL: @test2( |
| ; CHECK-NEXT: [[Q:%.*]] = getelementptr i32, ptr [[P:%.*]], i32 1 |
| ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[Q]]) |
| ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[Q]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %Q = getelementptr i32, ptr %P, i32 1 |
| call void @llvm.lifetime.start.p0(i64 4, ptr %Q) |
| store i32 0, ptr %Q ;; This store is dead. |
| call void @llvm.lifetime.end.p0(i64 4, ptr %Q) |
| ret void |
| } |
| |
| ; lifetime.end only marks the first two bytes of %A as dead. Make sure |
| ; `store i8 20, ptr %A.2 is not removed. |
| define void @test3_lifetime_end_partial() { |
| ; CHECK-LABEL: @test3_lifetime_end_partial( |
| ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 |
| ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 2, ptr [[A]]) |
| ; CHECK-NEXT: [[A_1:%.*]] = getelementptr i8, ptr [[A]], i64 1 |
| ; CHECK-NEXT: [[A_2:%.*]] = getelementptr i8, ptr [[A]], i64 2 |
| ; CHECK-NEXT: store i8 20, ptr [[A_2]], align 1 |
| ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 2, ptr [[A]]) |
| ; CHECK-NEXT: call void @use(ptr [[A_1]]) |
| ; CHECK-NEXT: ret void |
| ; |
| %A = alloca i32 |
| |
| call void @llvm.lifetime.start.p0(i64 2, ptr %A) |
| %A.1 = getelementptr i8, ptr %A, i64 1 |
| %A.2 = getelementptr i8, ptr %A, i64 2 |
| |
| store i8 0, ptr %A |
| store i8 10, ptr %A.1 |
| store i8 20, ptr %A.2 |
| |
| call void @llvm.lifetime.end.p0(i64 2, ptr %A) |
| call void @use(ptr %A.1) |
| ret void |
| } |
| |
| ; lifetime.end only marks the first two bytes of %A as dead. Make sure |
| ; `store i8 20, ptr %A.2 is not removed. |
| define void @test4_lifetime_end_partial_loop() { |
| ; CHECK-LABEL: @test4_lifetime_end_partial_loop( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ] |
| ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 2, ptr [[A]]) |
| ; CHECK-NEXT: [[A_1:%.*]] = getelementptr i8, ptr [[A]], i64 1 |
| ; CHECK-NEXT: [[A_2:%.*]] = getelementptr i8, ptr [[A]], i64 2 |
| ; CHECK-NEXT: call void @use(ptr [[A_1]]) |
| ; CHECK-NEXT: store i8 20, ptr [[A_2]], align 1 |
| ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 2, ptr [[A]]) |
| ; CHECK-NEXT: [[IV_NEXT]] = add i8 [[IV]], 10 |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i8 [[IV_NEXT]], 10 |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label [[EXIT:%.*]], label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %A = alloca i32 |
| |
| br label %loop |
| |
| loop: |
| %iv = phi i8 [ 0, %entry ], [ %iv.next, %loop ] |
| call void @llvm.lifetime.start.p0(i64 2, ptr %A) |
| %A.1 = getelementptr i8, ptr %A, i64 1 |
| %A.2 = getelementptr i8, ptr %A, i64 2 |
| |
| call void @use(ptr %A.1) |
| |
| store i8 20, ptr %A.2 |
| store i8 10, ptr %A.1 |
| store i8 0, ptr %A |
| call void @llvm.lifetime.end.p0(i64 2, ptr %A) |
| |
| %iv.next = add i8 %iv, 10 |
| %exitcond = icmp eq i8 %iv.next, 10 |
| br i1 %exitcond, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| ; lifetime.end only marks the first two bytes of %A as dead. Make sure |
| ; `store i8 20, ptr %A.2 is not removed. |
| define void @test5_lifetime_end_partial(ptr %A) { |
| ; CHECK-LABEL: @test5_lifetime_end_partial( |
| ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 2, ptr [[A:%.*]]) |
| ; CHECK-NEXT: [[A_1:%.*]] = getelementptr i8, ptr [[A]], i64 1 |
| ; CHECK-NEXT: [[A_2:%.*]] = getelementptr i8, ptr [[A]], i64 2 |
| ; CHECK-NEXT: store i8 20, ptr [[A_2]], align 1 |
| ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 2, ptr [[A]]) |
| ; CHECK-NEXT: call void @use(ptr [[A_1]]) |
| ; CHECK-NEXT: store i8 30, ptr [[A_1]], align 1 |
| ; CHECK-NEXT: store i8 40, ptr [[A_2]], align 1 |
| ; CHECK-NEXT: ret void |
| ; |
| |
| call void @llvm.lifetime.start.p0(i64 2, ptr %A) |
| %A.1 = getelementptr i8, ptr %A, i64 1 |
| %A.2 = getelementptr i8, ptr %A, i64 2 |
| |
| store i8 0, ptr %A |
| store i8 10, ptr %A.1 |
| store i8 20, ptr %A.2 |
| |
| call void @llvm.lifetime.end.p0(i64 2, ptr %A) |
| |
| call void @use(ptr %A.1) |
| store i8 30, ptr %A.1 |
| store i8 40, ptr %A.2 |
| ret void |
| } |
| |
| declare void @use(ptr) readonly |