summaryrefslogtreecommitdiff
path: root/test/Transforms/Mem2Reg/preserve-nonnull-load-metadata.ll
diff options
context:
space:
mode:
Diffstat (limited to 'test/Transforms/Mem2Reg/preserve-nonnull-load-metadata.ll')
-rw-r--r--test/Transforms/Mem2Reg/preserve-nonnull-load-metadata.ll89
1 files changed, 89 insertions, 0 deletions
diff --git a/test/Transforms/Mem2Reg/preserve-nonnull-load-metadata.ll b/test/Transforms/Mem2Reg/preserve-nonnull-load-metadata.ll
new file mode 100644
index 000000000000..33a5b124c555
--- /dev/null
+++ b/test/Transforms/Mem2Reg/preserve-nonnull-load-metadata.ll
@@ -0,0 +1,89 @@
+; RUN: opt < %s -mem2reg -S | FileCheck %s
+
+; This tests that mem2reg preserves the !nonnull metadata on loads
+; from allocas that get optimized out.
+
+; Check the case where the alloca in question has a single store.
+define float* @single_store(float** %arg) {
+; CHECK-LABEL: define float* @single_store
+; CHECK: %arg.load = load float*, float** %arg, align 8
+; CHECK: [[ASSUME:%(.*)]] = icmp ne float* %arg.load, null
+; CHECK: call void @llvm.assume(i1 {{.*}}[[ASSUME]])
+; CHECK: ret float* %arg.load
+entry:
+ %buf = alloca float*
+ %arg.load = load float*, float** %arg, align 8
+ store float* %arg.load, float** %buf, align 8
+ %buf.load = load float*, float **%buf, !nonnull !0
+ ret float* %buf.load
+}
+
+; Check the case where the alloca in question has more than one
+; store but still within one basic block.
+define float* @single_block(float** %arg) {
+; CHECK-LABEL: define float* @single_block
+; CHECK: %arg.load = load float*, float** %arg, align 8
+; CHECK: [[ASSUME:%(.*)]] = icmp ne float* %arg.load, null
+; CHECK: call void @llvm.assume(i1 {{.*}}[[ASSUME]])
+; CHECK: ret float* %arg.load
+entry:
+ %buf = alloca float*
+ %arg.load = load float*, float** %arg, align 8
+ store float* null, float** %buf, align 8
+ store float* %arg.load, float** %buf, align 8
+ %buf.load = load float*, float **%buf, !nonnull !0
+ ret float* %buf.load
+}
+
+; Check the case where the alloca in question has more than one
+; store and also reads ands writes in multiple blocks.
+define float* @multi_block(float** %arg) {
+; CHECK-LABEL: define float* @multi_block
+; CHECK-LABEL: entry:
+; CHECK: %arg.load = load float*, float** %arg, align 8
+; CHECK: br label %next
+; CHECK-LABEL: next:
+; CHECK: [[ASSUME:%(.*)]] = icmp ne float* %arg.load, null
+; CHECK: call void @llvm.assume(i1 {{.*}}[[ASSUME]])
+; CHECK: ret float* %arg.load
+entry:
+ %buf = alloca float*
+ %arg.load = load float*, float** %arg, align 8
+ store float* null, float** %buf, align 8
+ br label %next
+next:
+ store float* %arg.load, float** %buf, align 8
+ %buf.load = load float*, float** %buf, !nonnull !0
+ ret float* %buf.load
+}
+
+; Check that we don't add an assume if it's not
+; necessary i.e. the value is already implied to be nonnull
+define float* @no_assume(float** %arg) {
+; CHECK-LABEL: define float* @no_assume
+; CHECK-LABEL: entry:
+; CHECK: %arg.load = load float*, float** %arg, align 8
+; CHECK: %cn = icmp ne float* %arg.load, null
+; CHECK: br i1 %cn, label %next, label %fin
+; CHECK-LABEL: next:
+; CHECK-NOT: call void @llvm.assume
+; CHECK: ret float* %arg.load
+; CHECK-LABEL: fin:
+; CHECK: ret float* null
+entry:
+ %buf = alloca float*
+ %arg.load = load float*, float** %arg, align 8
+ %cn = icmp ne float* %arg.load, null
+ br i1 %cn, label %next, label %fin
+next:
+; At this point the above nonnull check ensures that
+; the value %arg.load is nonnull in this block and thus
+; we need not add the assume.
+ store float* %arg.load, float** %buf, align 8
+ %buf.load = load float*, float** %buf, !nonnull !0
+ ret float* %buf.load
+fin:
+ ret float* null
+}
+
+!0 = !{}