| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt < %s -aa-pipeline=basic-aa -passes='dse,verify<memoryssa>' -S | FileCheck %s |
| |
| ; There exists a dominating condition in the entry block, not the immediate |
| ; dominator for the store, the edge entry->if.eq dominates the store, no |
| ; clobber in between, the store is redundant. |
| define void @remove_tautological_store_via_dom_condition(ptr %x, i1 %c) { |
| ; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition( |
| ; CHECK-SAME: ptr [[X:%.*]], i1 [[C:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0 |
| ; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[END:.*]] |
| ; CHECK: [[THEN]]: |
| ; CHECK-NEXT: br i1 [[C]], label %[[IF_EQ:.*]], label %[[IF_ELSE:.*]] |
| ; CHECK: [[IF_EQ]]: |
| ; CHECK-NEXT: br label %[[JOIN:.*]] |
| ; CHECK: [[IF_ELSE]]: |
| ; CHECK-NEXT: br label %[[JOIN]] |
| ; CHECK: [[JOIN]]: |
| ; CHECK-NEXT: br label %[[INNER:.*]] |
| ; CHECK: [[INNER]]: |
| ; CHECK-NEXT: br label %[[END]] |
| ; CHECK: [[END]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %val = load i32, ptr %x, align 4 |
| %cmp = icmp eq i32 %val, 0 |
| br i1 %cmp, label %then, label %end |
| |
| then: |
| br i1 %c, label %if.eq, label %if.else |
| |
| if.eq: |
| br label %join |
| |
| if.else: |
| br label %join |
| |
| join: |
| br label %inner |
| |
| inner: |
| store i32 0, ptr %x, align 4 |
| br label %end |
| |
| end: |
| ret void |
| } |
| |
| ; There exists a dominating condition in block then, the edge then->if.eq immediately |
| ; dominates the first store, but does not dominate the second one, no clobber |
| ; in between, the first store is redundant. |
| define void @remove_tautological_store_via_dom_condition_2(ptr %x, i1 %c) { |
| ; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition_2( |
| ; CHECK-SAME: ptr [[X:%.*]], i1 [[C:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: br i1 [[C]], label %[[THEN:.*]], label %[[END:.*]] |
| ; CHECK: [[THEN]]: |
| ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0 |
| ; CHECK-NEXT: br i1 [[CMP]], label %[[IF_EQ:.*]], label %[[IF_ELSE:.*]] |
| ; CHECK: [[IF_EQ]]: |
| ; CHECK-NEXT: br label %[[JOIN:.*]] |
| ; CHECK: [[IF_ELSE]]: |
| ; CHECK-NEXT: br label %[[JOIN]] |
| ; CHECK: [[JOIN]]: |
| ; CHECK-NEXT: store i32 0, ptr [[X]], align 4 |
| ; CHECK-NEXT: br label %[[INNER:.*]] |
| ; CHECK: [[INNER]]: |
| ; CHECK-NEXT: br label %[[END]] |
| ; CHECK: [[END]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| br i1 %c, label %then, label %end |
| |
| then: |
| %val = load i32, ptr %x, align 4 |
| %cmp = icmp eq i32 %val, 0 |
| br i1 %cmp, label %if.eq, label %if.else |
| |
| if.eq: |
| store i32 0, ptr %x, align 4 |
| br label %join |
| |
| if.else: |
| br label %join |
| |
| join: |
| store i32 0, ptr %x, align 4 |
| br label %inner |
| |
| inner: |
| br label %end |
| |
| end: |
| ret void |
| } |
| |
| ; There exist two dominating conditions in the CFG, the edges entry->if.eq and |
| ; then->if.eq dominate the stores, no clobber in between, the stores are redundant. |
| define void @remove_tautological_store_via_dom_condition_3(ptr %x, ptr %y, i1 %c) { |
| ; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition_3( |
| ; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]], i1 [[C:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0 |
| ; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[END:.*]] |
| ; CHECK: [[THEN]]: |
| ; CHECK-NEXT: [[VAL_2:%.*]] = load i32, ptr [[Y]], align 4 |
| ; CHECK-NEXT: [[CMP_2:%.*]] = icmp eq i32 [[VAL_2]], 0 |
| ; CHECK-NEXT: br i1 [[CMP_2]], label %[[IF_EQ:.*]], label %[[IF_ELSE:.*]] |
| ; CHECK: [[IF_EQ]]: |
| ; CHECK-NEXT: br label %[[JOIN:.*]] |
| ; CHECK: [[IF_ELSE]]: |
| ; CHECK-NEXT: br label %[[JOIN]] |
| ; CHECK: [[JOIN]]: |
| ; CHECK-NEXT: br label %[[INNER:.*]] |
| ; CHECK: [[INNER]]: |
| ; CHECK-NEXT: br label %[[END]] |
| ; CHECK: [[END]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %val = load i32, ptr %x, align 4 |
| %cmp = icmp eq i32 %val, 0 |
| br i1 %cmp, label %then, label %end |
| |
| then: |
| %val.2 = load i32, ptr %y, align 4 |
| %cmp.2 = icmp eq i32 %val.2, 0 |
| br i1 %cmp.2, label %if.eq, label %if.else |
| |
| if.eq: |
| store i32 0, ptr %x, align 4 |
| store i32 0, ptr %y, align 4 |
| br label %join |
| |
| if.else: |
| br label %join |
| |
| join: |
| br label %inner |
| |
| inner: |
| br label %end |
| |
| end: |
| ret void |
| } |
| |
| ; Negative tests. |
| |
| ; There exists a dominating condition in the entry block, however, |
| ; the pointer whose value is implied is clobbered in between. |
| define void @remove_tautological_store_via_dom_condition_clobber_between(ptr %x, i1 %c) { |
| ; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition_clobber_between( |
| ; CHECK-SAME: ptr [[X:%.*]], i1 [[C:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0 |
| ; CHECK-NEXT: br i1 [[CMP]], label %[[IF_EQ:.*]], label %[[END:.*]] |
| ; CHECK: [[IF_EQ]]: |
| ; CHECK-NEXT: br label %[[NEXT:.*]] |
| ; CHECK: [[NEXT]]: |
| ; CHECK-NEXT: call void @opaque(ptr [[X]]) |
| ; CHECK-NEXT: br i1 [[C]], label %[[INNER:.*]], label %[[END]] |
| ; CHECK: [[INNER]]: |
| ; CHECK-NEXT: store i32 0, ptr [[X]], align 4 |
| ; CHECK-NEXT: br label %[[END]] |
| ; CHECK: [[END]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %val = load i32, ptr %x, align 4 |
| %cmp = icmp eq i32 %val, 0 |
| br i1 %cmp, label %if.eq, label %end |
| |
| if.eq: |
| br label %next |
| |
| next: |
| call void @opaque(ptr %x) |
| br i1 %c, label %inner, label %end |
| |
| inner: |
| store i32 0, ptr %x, align 4 |
| br label %end |
| |
| end: |
| ret void |
| } |
| |
| ; Volatile stores should not be eliminated. |
| define void @remove_tautological_store_via_dom_condition_volatile_store(ptr %x, i1 %c) { |
| ; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition_volatile_store( |
| ; CHECK-SAME: ptr [[X:%.*]], i1 [[C:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0 |
| ; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[END:.*]] |
| ; CHECK: [[THEN]]: |
| ; CHECK-NEXT: br i1 [[C]], label %[[IF_EQ:.*]], label %[[IF_ELSE:.*]] |
| ; CHECK: [[IF_EQ]]: |
| ; CHECK-NEXT: br label %[[JOIN:.*]] |
| ; CHECK: [[IF_ELSE]]: |
| ; CHECK-NEXT: br label %[[JOIN]] |
| ; CHECK: [[JOIN]]: |
| ; CHECK-NEXT: store volatile i32 0, ptr [[X]], align 4 |
| ; CHECK-NEXT: br label %[[END]] |
| ; CHECK: [[END]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %val = load i32, ptr %x, align 4 |
| %cmp = icmp eq i32 %val, 0 |
| br i1 %cmp, label %then, label %end |
| |
| then: |
| br i1 %c, label %if.eq, label %if.else |
| |
| if.eq: |
| br label %join |
| |
| if.else: |
| br label %join |
| |
| join: |
| store volatile i32 0, ptr %x, align 4 |
| br label %end |
| |
| end: |
| ret void |
| } |
| |
| ; Atomic stores should not be eliminated. |
| define void @remove_tautological_store_via_dom_condition_atomic_store(ptr %x, i1 %c) { |
| ; CHECK-LABEL: define void @remove_tautological_store_via_dom_condition_atomic_store( |
| ; CHECK-SAME: ptr [[X:%.*]], i1 [[C:%.*]]) { |
| ; CHECK-NEXT: [[ENTRY:.*:]] |
| ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[X]], align 4 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[VAL]], 0 |
| ; CHECK-NEXT: br i1 [[CMP]], label %[[THEN:.*]], label %[[END:.*]] |
| ; CHECK: [[THEN]]: |
| ; CHECK-NEXT: br i1 [[C]], label %[[IF_EQ:.*]], label %[[IF_ELSE:.*]] |
| ; CHECK: [[IF_EQ]]: |
| ; CHECK-NEXT: br label %[[JOIN:.*]] |
| ; CHECK: [[IF_ELSE]]: |
| ; CHECK-NEXT: br label %[[JOIN]] |
| ; CHECK: [[JOIN]]: |
| ; CHECK-NEXT: store atomic i32 0, ptr [[X]] release, align 4 |
| ; CHECK-NEXT: br label %[[END]] |
| ; CHECK: [[END]]: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %val = load i32, ptr %x, align 4 |
| %cmp = icmp eq i32 %val, 0 |
| br i1 %cmp, label %then, label %end |
| |
| then: |
| br i1 %c, label %if.eq, label %if.else |
| |
| if.eq: |
| br label %join |
| |
| if.else: |
| br label %join |
| |
| join: |
| store atomic i32 0, ptr %x release, align 4 |
| br label %end |
| |
| end: |
| ret void |
| } |
| |
| declare void @opaque(ptr) |