xref: /llvm-project/llvm/test/Transforms/Mem2Reg/preserve-nonnull-load-metadata.ll (revision c6973ade4c46e28b1be9e1f5d873ca9a59197418)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=mem2reg -S | FileCheck %s
3
4; This tests that mem2reg preserves the !nonnull metadata on loads
5; from allocas that get optimized out.
6
7; Check the case where the alloca in question has a single store.
8define ptr @single_store_noundef(ptr %arg) {
9; CHECK-LABEL: @single_store_noundef(
10; CHECK-NEXT:  entry:
11; CHECK-NEXT:    [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
12; CHECK-NEXT:    [[TMP0:%.*]] = icmp ne ptr [[ARG_LOAD]], null
13; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP0]])
14; CHECK-NEXT:    ret ptr [[ARG_LOAD]]
15;
16entry:
17  %buf = alloca ptr
18  %arg.load = load ptr, ptr %arg, align 8
19  store ptr %arg.load, ptr %buf, align 8
20  %buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0
21  ret ptr %buf.load
22}
23
24define ptr @single_store_missing_noundef(ptr %arg) {
25; CHECK-LABEL: @single_store_missing_noundef(
26; CHECK-NEXT:  entry:
27; CHECK-NEXT:    [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
28; CHECK-NEXT:    ret ptr [[ARG_LOAD]]
29;
30entry:
31  %buf = alloca ptr
32  %arg.load = load ptr, ptr %arg, align 8
33  store ptr %arg.load, ptr %buf, align 8
34  %buf.load = load ptr, ptr %buf, !nonnull !0
35  ret ptr %buf.load
36}
37
38; Check the case where the alloca in question has more than one
39; store but still within one basic block.
40define ptr @single_block_noundef(ptr %arg) {
41; CHECK-LABEL: @single_block_noundef(
42; CHECK-NEXT:  entry:
43; CHECK-NEXT:    [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
44; CHECK-NEXT:    [[TMP0:%.*]] = icmp ne ptr [[ARG_LOAD]], null
45; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP0]])
46; CHECK-NEXT:    ret ptr [[ARG_LOAD]]
47;
48entry:
49  %buf = alloca ptr
50  %arg.load = load ptr, ptr %arg, align 8
51  store ptr null, ptr %buf, align 8
52  store ptr %arg.load, ptr %buf, align 8
53  %buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0
54  ret ptr %buf.load
55}
56
57define ptr @single_block_missing_noundef(ptr %arg) {
58; CHECK-LABEL: @single_block_missing_noundef(
59; CHECK-NEXT:  entry:
60; CHECK-NEXT:    [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
61; CHECK-NEXT:    ret ptr [[ARG_LOAD]]
62;
63entry:
64  %buf = alloca ptr
65  %arg.load = load ptr, ptr %arg, align 8
66  store ptr null, ptr %buf, align 8
67  store ptr %arg.load, ptr %buf, align 8
68  %buf.load = load ptr, ptr %buf, !nonnull !0
69  ret ptr %buf.load
70}
71
72; Check the case where the alloca in question has more than one
73; store and also reads ands writes in multiple blocks.
74define ptr @multi_block_noundef(ptr %arg) {
75; CHECK-LABEL: @multi_block_noundef(
76; CHECK-NEXT:  entry:
77; CHECK-NEXT:    [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
78; CHECK-NEXT:    br label [[NEXT:%.*]]
79; CHECK:       next:
80; CHECK-NEXT:    [[TMP0:%.*]] = icmp ne ptr [[ARG_LOAD]], null
81; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP0]])
82; CHECK-NEXT:    ret ptr [[ARG_LOAD]]
83;
84entry:
85  %buf = alloca ptr
86  %arg.load = load ptr, ptr %arg, align 8
87  store ptr null, ptr %buf, align 8
88  br label %next
89next:
90  store ptr %arg.load, ptr %buf, align 8
91  %buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0
92  ret ptr %buf.load
93}
94
95define ptr @multi_block_missing_noundef(ptr %arg) {
96; CHECK-LABEL: @multi_block_missing_noundef(
97; CHECK-NEXT:  entry:
98; CHECK-NEXT:    [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
99; CHECK-NEXT:    br label [[NEXT:%.*]]
100; CHECK:       next:
101; CHECK-NEXT:    ret ptr [[ARG_LOAD]]
102;
103entry:
104  %buf = alloca ptr
105  %arg.load = load ptr, ptr %arg, align 8
106  store ptr null, ptr %buf, align 8
107  br label %next
108next:
109  store ptr %arg.load, ptr %buf, align 8
110  %buf.load = load ptr, ptr %buf, !nonnull !0
111  ret ptr %buf.load
112}
113
114; Check that we don't add an assume if it's not
115; necessary i.e. the value is already implied to be nonnull
116define ptr @no_assume(ptr %arg) {
117; CHECK-LABEL: @no_assume(
118; CHECK-NEXT:  entry:
119; CHECK-NEXT:    [[ARG_LOAD:%.*]] = load ptr, ptr [[ARG:%.*]], align 8
120; CHECK-NEXT:    [[CN:%.*]] = icmp ne ptr [[ARG_LOAD]], null
121; CHECK-NEXT:    br i1 [[CN]], label [[NEXT:%.*]], label [[FIN:%.*]]
122; CHECK:       next:
123; CHECK-NEXT:    ret ptr [[ARG_LOAD]]
124; CHECK:       fin:
125; CHECK-NEXT:    ret ptr null
126;
127entry:
128  %buf = alloca ptr
129  %arg.load = load ptr, ptr %arg, align 8
130  %cn = icmp ne ptr %arg.load, null
131  br i1 %cn, label %next, label %fin
132next:
133; At this point the above nonnull check ensures that
134; the value %arg.load is nonnull in this block and thus
135; we need not add the assume.
136  store ptr %arg.load, ptr %buf, align 8
137  %buf.load = load ptr, ptr %buf, !nonnull !0
138  ret ptr %buf.load
139fin:
140  ret ptr null
141}
142
143define ptr @no_store_single_load_noundef() {
144; CHECK-LABEL: @no_store_single_load_noundef(
145; CHECK-NEXT:  entry:
146; CHECK-NEXT:    store i1 true, ptr poison, align 1
147; CHECK-NEXT:    ret ptr undef
148;
149entry:
150  %buf = alloca ptr
151  %buf.load = load ptr, ptr %buf, !noundef !0
152  ret ptr %buf.load
153}
154
155define ptr @no_store_multiple_loads_noundef(i1 %c) {
156; CHECK-LABEL: @no_store_multiple_loads_noundef(
157; CHECK-NEXT:  entry:
158; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
159; CHECK:       if:
160; CHECK-NEXT:    store i1 true, ptr poison, align 1
161; CHECK-NEXT:    ret ptr undef
162; CHECK:       else:
163; CHECK-NEXT:    store i1 true, ptr poison, align 1
164; CHECK-NEXT:    ret ptr undef
165;
166entry:
167  %buf = alloca ptr
168  br i1 %c, label %if, label %else
169
170if:
171  %buf.load = load ptr, ptr %buf, !noundef !0
172  ret ptr %buf.load
173
174  else:
175  %buf.load2 = load ptr, ptr %buf, !noundef !0
176  ret ptr %buf.load2
177}
178
179define ptr @no_store_single_load_nonnull_noundef() {
180; CHECK-LABEL: @no_store_single_load_nonnull_noundef(
181; CHECK-NEXT:  entry:
182; CHECK-NEXT:    store i1 true, ptr poison, align 1
183; CHECK-NEXT:    ret ptr undef
184;
185entry:
186  %buf = alloca ptr
187  %buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0
188  ret ptr %buf.load
189}
190
191define ptr @no_store_multiple_loads_nonnull_noundef(i1 %c) {
192; CHECK-LABEL: @no_store_multiple_loads_nonnull_noundef(
193; CHECK-NEXT:  entry:
194; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
195; CHECK:       if:
196; CHECK-NEXT:    store i1 true, ptr poison, align 1
197; CHECK-NEXT:    ret ptr undef
198; CHECK:       else:
199; CHECK-NEXT:    store i1 true, ptr poison, align 1
200; CHECK-NEXT:    ret ptr undef
201;
202entry:
203  %buf = alloca ptr
204  br i1 %c, label %if, label %else
205
206if:
207  %buf.load = load ptr, ptr %buf, !nonnull !0, !noundef !0
208  ret ptr %buf.load
209
210  else:
211  %buf.load2 = load ptr, ptr %buf, !nonnull !0, !noundef !0
212  ret ptr %buf.load2
213}
214
215!0 = !{}
216