aboutsummaryrefslogtreecommitdiff
path: root/test/Transforms/EarlyCSE/invariant-loads.ll
diff options
context:
space:
mode:
Diffstat (limited to 'test/Transforms/EarlyCSE/invariant-loads.ll')
-rw-r--r--test/Transforms/EarlyCSE/invariant-loads.ll99
1 files changed, 99 insertions, 0 deletions
diff --git a/test/Transforms/EarlyCSE/invariant-loads.ll b/test/Transforms/EarlyCSE/invariant-loads.ll
new file mode 100644
index 000000000000..04c7dd1372d9
--- /dev/null
+++ b/test/Transforms/EarlyCSE/invariant-loads.ll
@@ -0,0 +1,99 @@
+; RUN: opt -S -early-cse < %s | FileCheck %s
+
+declare void @clobber_and_use(i32)
+
+define void @f_0(i32* %ptr) {
+; CHECK-LABEL: @f_0(
+; CHECK: %val0 = load i32, i32* %ptr, !invariant.load !0
+; CHECK: call void @clobber_and_use(i32 %val0)
+; CHECK: call void @clobber_and_use(i32 %val0)
+; CHECK: call void @clobber_and_use(i32 %val0)
+; CHECK: ret void
+
+ %val0 = load i32, i32* %ptr, !invariant.load !{}
+ call void @clobber_and_use(i32 %val0)
+ %val1 = load i32, i32* %ptr, !invariant.load !{}
+ call void @clobber_and_use(i32 %val1)
+ %val2 = load i32, i32* %ptr, !invariant.load !{}
+ call void @clobber_and_use(i32 %val2)
+ ret void
+}
+
+define void @f_1(i32* %ptr) {
+; We can forward invariant loads to non-invariant loads, since once an
+; invariant load has executed, the location loaded from is known to be
+; unchanging.
+
+; CHECK-LABEL: @f_1(
+; CHECK: %val0 = load i32, i32* %ptr, !invariant.load !0
+; CHECK: call void @clobber_and_use(i32 %val0)
+; CHECK: call void @clobber_and_use(i32 %val0)
+
+ %val0 = load i32, i32* %ptr, !invariant.load !{}
+ call void @clobber_and_use(i32 %val0)
+ %val1 = load i32, i32* %ptr
+ call void @clobber_and_use(i32 %val1)
+ ret void
+}
+
+define void @f_2(i32* %ptr) {
+; Negative test -- we can't forward a non-invariant load into an
+; invariant load.
+
+; CHECK-LABEL: @f_2(
+; CHECK: %val0 = load i32, i32* %ptr
+; CHECK: call void @clobber_and_use(i32 %val0)
+; CHECK: %val1 = load i32, i32* %ptr, !invariant.load !0
+; CHECK: call void @clobber_and_use(i32 %val1)
+
+ %val0 = load i32, i32* %ptr
+ call void @clobber_and_use(i32 %val0)
+ %val1 = load i32, i32* %ptr, !invariant.load !{}
+ call void @clobber_and_use(i32 %val1)
+ ret void
+}
+
+define void @f_3(i1 %cond, i32* %ptr) {
+; CHECK-LABEL: @f_3(
+ %val0 = load i32, i32* %ptr, !invariant.load !{}
+ call void @clobber_and_use(i32 %val0)
+ br i1 %cond, label %left, label %right
+
+; CHECK: %val0 = load i32, i32* %ptr, !invariant.load !0
+; CHECK: left:
+; CHECK-NEXT: call void @clobber_and_use(i32 %val0)
+
+left:
+ %val1 = load i32, i32* %ptr
+ call void @clobber_and_use(i32 %val1)
+ ret void
+
+right:
+ ret void
+}
+
+define void @f_4(i1 %cond, i32* %ptr) {
+; Negative test -- can't forward %val0 to %va1 because that'll break
+; def-dominates-use.
+
+; CHECK-LABEL: @f_4(
+ br i1 %cond, label %left, label %merge
+
+left:
+; CHECK: left:
+; CHECK-NEXT: %val0 = load i32, i32* %ptr, !invariant.load !
+; CHECK-NEXT: call void @clobber_and_use(i32 %val0)
+
+ %val0 = load i32, i32* %ptr, !invariant.load !{}
+ call void @clobber_and_use(i32 %val0)
+ br label %merge
+
+merge:
+; CHECK: merge:
+; CHECK-NEXT: %val1 = load i32, i32* %ptr
+; CHECK-NEXT: call void @clobber_and_use(i32 %val1)
+
+ %val1 = load i32, i32* %ptr
+ call void @clobber_and_use(i32 %val1)
+ ret void
+}