blob: 53f570e2b3c5372a78b6a30039070723f9126b67 [file] [edit]
; 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)