1; RUN: opt < %s -passes=gvn -S | FileCheck %s 2 3%struct.A = type { ptr } 4@_ZTV1A = available_externally unnamed_addr constant [3 x ptr] [ptr null, ptr @_ZTI1A, ptr @_ZN1A3fooEv], align 8 5@_ZTI1A = external constant ptr 6 7@unknownPtr = external global i8 8 9; CHECK-LABEL: define i8 @simple() { 10define i8 @simple() { 11entry: 12 %ptr = alloca i8 13 store i8 42, ptr %ptr, !invariant.group !0 14 call void @foo(ptr %ptr) 15 16 %a = load i8, ptr %ptr, !invariant.group !0 17 %b = load i8, ptr %ptr, !invariant.group !0 18 %c = load i8, ptr %ptr, !invariant.group !0 19; CHECK: ret i8 42 20 ret i8 %a 21} 22 23; CHECK-LABEL: define i8 @optimizable1() { 24define i8 @optimizable1() { 25entry: 26 %ptr = alloca i8 27 store i8 42, ptr %ptr, !invariant.group !0 28 %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr) 29 %a = load i8, ptr %ptr, !invariant.group !0 30 31 call void @foo(ptr %ptr2); call to use %ptr2 32; CHECK: ret i8 42 33 ret i8 %a 34} 35 36; CHECK-LABEL: define i8 @optimizable2() { 37define i8 @optimizable2() { 38entry: 39 %ptr = alloca i8 40 store i8 42, ptr %ptr, !invariant.group !0 41 call void @foo(ptr %ptr) 42 43 store i8 13, ptr %ptr ; can't use this store with invariant.group 44 %a = load i8, ptr %ptr 45 call void @bar(i8 %a) ; call to use %a 46 47 call void @foo(ptr %ptr) 48 %b = load i8, ptr %ptr, !invariant.group !0 49 50; CHECK: ret i8 42 51 ret i8 %b 52} 53 54; CHECK-LABEL: define i1 @proveEqualityForStrip( 55define i1 @proveEqualityForStrip(ptr %a) { 56; FIXME: The first call could be also removed by GVN. Right now 57; DCE removes it. The second call is CSE'd with the first one. 58; CHECK: %b1 = call ptr @llvm.strip.invariant.group.p0(ptr %a) 59 %b1 = call ptr @llvm.strip.invariant.group.p0(ptr %a) 60; CHECK-NOT: llvm.strip.invariant.group 61 %b2 = call ptr @llvm.strip.invariant.group.p0(ptr %a) 62 %r = icmp eq ptr %b1, %b2 63; CHECK: ret i1 true 64 ret i1 %r 65} 66; CHECK-LABEL: define i8 @unoptimizable1() { 67define i8 @unoptimizable1() { 68entry: 69 %ptr = alloca i8 70 store i8 42, ptr %ptr 71 call void @foo(ptr %ptr) 72 %a = load i8, ptr %ptr, !invariant.group !0 73; CHECK: ret i8 %a 74 ret i8 %a 75} 76 77; CHECK-LABEL: define void @indirectLoads() { 78define void @indirectLoads() { 79entry: 80 %a = alloca ptr, align 8 81 82 %call = call ptr @getPointer(ptr null) 83 call void @_ZN1AC1Ev(ptr %call) 84 85; CHECK: %vtable = load {{.*}} !invariant.group 86 %vtable = load ptr, ptr %call, align 8, !invariant.group !0 87 %cmp.vtables = icmp eq ptr %vtable, getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2) 88 call void @llvm.assume(i1 %cmp.vtables) 89 90 store ptr %call, ptr %a, align 8 91 %0 = load ptr, ptr %a, align 8 92 93; CHECK: call void @_ZN1A3fooEv( 94 %vtable1 = load ptr, ptr %0, align 8, !invariant.group !0 95 %1 = load ptr, ptr %vtable1, align 8 96 call void %1(ptr %0) 97 %2 = load ptr, ptr %a, align 8 98 99; CHECK: call void @_ZN1A3fooEv( 100 %vtable2 = load ptr, ptr %2, align 8, !invariant.group !0 101 %3 = load ptr, ptr %vtable2, align 8 102 103 call void %3(ptr %2) 104 %4 = load ptr, ptr %a, align 8 105 106 %vtable4 = load ptr, ptr %4, align 8, !invariant.group !0 107 %5 = load ptr, ptr %vtable4, align 8 108; CHECK: call void @_ZN1A3fooEv( 109 call void %5(ptr %4) 110 111 %vtable5 = load ptr, ptr %call, align 8, !invariant.group !0 112 %6 = load ptr, ptr %vtable5, align 8 113; CHECK: call void @_ZN1A3fooEv( 114 call void %6(ptr %4) 115 116 ret void 117} 118 119; CHECK-LABEL: define void @combiningBitCastWithLoad() { 120define void @combiningBitCastWithLoad() { 121entry: 122 %a = alloca ptr, align 8 123 124 %call = call ptr @getPointer(ptr null) 125 call void @_ZN1AC1Ev(ptr %call) 126 127; CHECK: %vtable = load {{.*}} !invariant.group 128 %vtable = load ptr, ptr %call, align 8, !invariant.group !0 129 %cmp.vtables = icmp eq ptr %vtable, getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2) 130 131 store ptr %call, ptr %a, align 8 132; CHECK-NOT: !invariant.group 133 %0 = load ptr, ptr %a, align 8 134 135 %vtable1 = load ptr, ptr %0, align 8, !invariant.group !0 136 %1 = load ptr, ptr %vtable1, align 8 137 call void %1(ptr %0) 138 139 ret void 140} 141 142; CHECK-LABEL:define void @loadCombine() { 143define void @loadCombine() { 144enter: 145 %ptr = alloca i8 146 store i8 42, ptr %ptr 147 call void @foo(ptr %ptr) 148; CHECK: %[[A:.*]] = load i8, ptr %ptr, align 1, !invariant.group 149 %a = load i8, ptr %ptr, !invariant.group !0 150; CHECK-NOT: load 151 %b = load i8, ptr %ptr, !invariant.group !0 152; CHECK: call void @bar(i8 %[[A]]) 153 call void @bar(i8 %a) 154; CHECK: call void @bar(i8 %[[A]]) 155 call void @bar(i8 %b) 156 ret void 157} 158 159; CHECK-LABEL: define void @loadCombine1() { 160define void @loadCombine1() { 161enter: 162 %ptr = alloca i8 163 store i8 42, ptr %ptr 164 call void @foo(ptr %ptr) 165; CHECK: %[[D:.*]] = load i8, ptr %ptr, align 1, !invariant.group 166 %c = load i8, ptr %ptr 167; CHECK-NOT: load 168 %d = load i8, ptr %ptr, !invariant.group !0 169; CHECK: call void @bar(i8 %[[D]]) 170 call void @bar(i8 %c) 171; CHECK: call void @bar(i8 %[[D]]) 172 call void @bar(i8 %d) 173 ret void 174} 175 176; CHECK-LABEL: define void @loadCombine2() { 177define void @loadCombine2() { 178enter: 179 %ptr = alloca i8 180 store i8 42, ptr %ptr 181 call void @foo(ptr %ptr) 182; CHECK: %[[E:.*]] = load i8, ptr %ptr, align 1, !invariant.group 183 %e = load i8, ptr %ptr, !invariant.group !0 184; CHECK-NOT: load 185 %f = load i8, ptr %ptr 186; CHECK: call void @bar(i8 %[[E]]) 187 call void @bar(i8 %e) 188; CHECK: call void @bar(i8 %[[E]]) 189 call void @bar(i8 %f) 190 ret void 191} 192 193; CHECK-LABEL: define void @loadCombine3() { 194define void @loadCombine3() { 195enter: 196 %ptr = alloca i8 197 store i8 42, ptr %ptr 198 call void @foo(ptr %ptr) 199; CHECK: %[[E:.*]] = load i8, ptr %ptr, align 1, !invariant.group 200 %e = load i8, ptr %ptr, !invariant.group !0 201; CHECK-NOT: load 202 %f = load i8, ptr %ptr, !invariant.group !0 203; CHECK: call void @bar(i8 %[[E]]) 204 call void @bar(i8 %e) 205; CHECK: call void @bar(i8 %[[E]]) 206 call void @bar(i8 %f) 207 ret void 208} 209 210; CHECK-LABEL: define i8 @unoptimizable2() { 211define i8 @unoptimizable2() { 212entry: 213 %ptr = alloca i8 214 store i8 42, ptr %ptr 215 call void @foo(ptr %ptr) 216 %a = load i8, ptr %ptr 217 call void @foo(ptr %ptr) 218 %b = load i8, ptr %ptr, !invariant.group !0 219 220; CHECK: ret i8 %a 221 ret i8 %a 222} 223 224; CHECK-LABEL: define i8 @unoptimizable3() { 225define i8 @unoptimizable3() { 226entry: 227 %ptr = alloca i8 228 store i8 42, ptr %ptr, !invariant.group !0 229 %ptr2 = call ptr @getPointer(ptr %ptr) 230 %a = load i8, ptr %ptr2, !invariant.group !0 231 232; CHECK: ret i8 %a 233 ret i8 %a 234} 235 236; CHECK-LABEL: define i8 @optimizable4() { 237define i8 @optimizable4() { 238entry: 239 %ptr = alloca i8 240 store i8 42, ptr %ptr, !invariant.group !0 241 %ptr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr) 242; CHECK-NOT: load 243 %a = load i8, ptr %ptr2, !invariant.group !0 244 245; CHECK: ret i8 42 246 ret i8 %a 247} 248 249; CHECK-LABEL: define i8 @volatile1() { 250define i8 @volatile1() { 251entry: 252 %ptr = alloca i8 253 store i8 42, ptr %ptr, !invariant.group !0 254 call void @foo(ptr %ptr) 255 %a = load i8, ptr %ptr, !invariant.group !0 256 %b = load volatile i8, ptr %ptr 257; CHECK: call void @bar(i8 %b) 258 call void @bar(i8 %b) 259 260 %c = load volatile i8, ptr %ptr, !invariant.group !0 261; FIXME: we could change %c to 42, preserving volatile load 262; CHECK: call void @bar(i8 %c) 263 call void @bar(i8 %c) 264; CHECK: ret i8 42 265 ret i8 %a 266} 267 268; CHECK-LABEL: define i8 @volatile2() { 269define i8 @volatile2() { 270entry: 271 %ptr = alloca i8 272 store i8 42, ptr %ptr, !invariant.group !0 273 call void @foo(ptr %ptr) 274 %a = load i8, ptr %ptr, !invariant.group !0 275 %b = load volatile i8, ptr %ptr 276; CHECK: call void @bar(i8 %b) 277 call void @bar(i8 %b) 278 279 %c = load volatile i8, ptr %ptr, !invariant.group !0 280; FIXME: we could change %c to 42, preserving volatile load 281; CHECK: call void @bar(i8 %c) 282 call void @bar(i8 %c) 283; CHECK: ret i8 42 284 ret i8 %a 285} 286 287; CHECK-LABEL: define i8 @fun() { 288define i8 @fun() { 289entry: 290 %ptr = alloca i8 291 store i8 42, ptr %ptr, !invariant.group !0 292 call void @foo(ptr %ptr) 293 294 %a = load i8, ptr %ptr, !invariant.group !0 ; Can assume that value under %ptr didn't change 295; CHECK: call void @bar(i8 42) 296 call void @bar(i8 %a) 297 298 %newPtr = call ptr @getPointer(ptr %ptr) 299 %c = load i8, ptr %newPtr, !invariant.group !0 ; Can't assume anything, because we only have information about %ptr 300; CHECK: call void @bar(i8 %c) 301 call void @bar(i8 %c) 302 303 %unknownValue = load i8, ptr @unknownPtr 304; FIXME: Can assume that %unknownValue == 42 305; CHECK: store i8 %unknownValue, ptr %ptr, align 1, !invariant.group !0 306 store i8 %unknownValue, ptr %ptr, !invariant.group !0 307 308 %newPtr2 = call ptr @llvm.launder.invariant.group.p0(ptr %ptr) 309; CHECK-NOT: load 310 %d = load i8, ptr %newPtr2, !invariant.group !0 311; CHECK: ret i8 %unknownValue 312 ret i8 %d 313} 314 315; This test checks if invariant.group understands gep with zeros 316; CHECK-LABEL: define void @testGEP0() { 317define void @testGEP0() { 318 %a = alloca %struct.A, align 8 319 store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr %a, align 8, !invariant.group !0 320; CHECK: call void @_ZN1A3fooEv(ptr nonnull dereferenceable(8) %a) 321 call void @_ZN1A3fooEv(ptr nonnull dereferenceable(8) %a) ; This call may change vptr 322 %1 = load i8, ptr @unknownPtr, align 4 323 %2 = icmp eq i8 %1, 0 324 br i1 %2, label %_Z1gR1A.exit, label %3 325 326; This should be devirtualized by invariant.group 327 %4 = load ptr, ptr %a, align 8, !invariant.group !0 328 %5 = load ptr, ptr %4, align 8 329; CHECK: call void @_ZN1A3fooEv(ptr nonnull %a) 330 call void %5(ptr nonnull %a) 331 br label %_Z1gR1A.exit 332 333_Z1gR1A.exit: ; preds = %0, %3 334 ret void 335} 336 337; Check if no optimizations are performed with global pointers. 338; FIXME: we could do the optimizations if we would check if dependency comes 339; from the same function. 340; CHECK-LABEL: define void @testGlobal() { 341define void @testGlobal() { 342; CHECK: %a = load i8, ptr @unknownPtr, align 1, !invariant.group !0 343 %a = load i8, ptr @unknownPtr, !invariant.group !0 344 call void @foo2(ptr @unknownPtr, i8 %a) 345; CHECK: %1 = load i8, ptr @unknownPtr, align 1, !invariant.group !0 346 %1 = load i8, ptr @unknownPtr, !invariant.group !0 347 call void @bar(i8 %1) 348 349 call void @fooBit(ptr @unknownPtr, i1 1) 350; Adding regex because of canonicalization of bitcasts 351; CHECK: %2 = load i1, ptr {{.*}}, !invariant.group !0 352 %2 = load i1, ptr @unknownPtr, !invariant.group !0 353 call void @fooBit(ptr @unknownPtr, i1 %2) 354; CHECK: %3 = load i1, ptr {{.*}}, !invariant.group !0 355 %3 = load i1, ptr @unknownPtr, !invariant.group !0 356 call void @fooBit(ptr @unknownPtr, i1 %3) 357 ret void 358} 359; And in the case it is not global 360; CHECK-LABEL: define void @testNotGlobal() { 361define void @testNotGlobal() { 362 %a = alloca i8 363 call void @foo(ptr %a) 364; CHECK: %b = load i8, ptr %a, align 1, !invariant.group !0 365 %b = load i8, ptr %a, !invariant.group !0 366 call void @foo2(ptr %a, i8 %b) 367 368 %1 = load i8, ptr %a, !invariant.group !0 369; CHECK: call void @bar(i8 %b) 370 call void @bar(i8 %1) 371 372 call void @fooBit(ptr %a, i1 1) 373; CHECK: %1 = trunc i8 %b to i1 374 %2 = load i1, ptr %a, !invariant.group !0 375; CHECK-NEXT: call void @fooBit(ptr %a, i1 %1) 376 call void @fooBit(ptr %a, i1 %2) 377 %3 = load i1, ptr %a, !invariant.group !0 378; CHECK-NEXT: call void @fooBit(ptr %a, i1 %1) 379 call void @fooBit(ptr %a, i1 %3) 380 ret void 381} 382 383; CHECK-LABEL: define void @handling_loops() 384define void @handling_loops() { 385 %a = alloca %struct.A, align 8 386 store ptr getelementptr inbounds ([3 x ptr], ptr @_ZTV1A, i64 0, i64 2), ptr %a, align 8, !invariant.group !0 387 %1 = load i8, ptr @unknownPtr, align 4 388 %2 = icmp sgt i8 %1, 0 389 br i1 %2, label %.lr.ph.i, label %_Z2g2R1A.exit 390 391.lr.ph.i: ; preds = %0 392 %3 = load i8, ptr @unknownPtr, align 4 393 %4 = icmp sgt i8 %3, 1 394 br i1 %4, label %._crit_edge.preheader, label %_Z2g2R1A.exit 395 396._crit_edge.preheader: ; preds = %.lr.ph.i 397 br label %._crit_edge 398 399._crit_edge: ; preds = %._crit_edge.preheader, %._crit_edge 400 %5 = phi i8 [ %7, %._crit_edge ], [ 1, %._crit_edge.preheader ] 401 %.pre = load ptr, ptr %a, align 8, !invariant.group !0 402 %6 = load ptr, ptr %.pre, align 8 403 ; CHECK: call void @_ZN1A3fooEv(ptr nonnull %a) 404 call void %6(ptr nonnull %a) #3 405 ; CHECK-NOT: call void % 406 %7 = add nuw nsw i8 %5, 1 407 %8 = load i8, ptr @unknownPtr, align 4 408 %9 = icmp slt i8 %7, %8 409 br i1 %9, label %._crit_edge, label %_Z2g2R1A.exit.loopexit 410 411_Z2g2R1A.exit.loopexit: ; preds = %._crit_edge 412 br label %_Z2g2R1A.exit 413 414_Z2g2R1A.exit: ; preds = %_Z2g2R1A.exit.loopexit, %.lr.ph.i, %0 415 ret void 416} 417 418 419declare void @foo(ptr) 420declare void @foo2(ptr, i8) 421declare void @bar(i8) 422declare ptr @getPointer(ptr) 423declare void @_ZN1A3fooEv(ptr) 424declare void @_ZN1AC1Ev(ptr) 425declare void @fooBit(ptr, i1) 426 427declare ptr @llvm.launder.invariant.group.p0(ptr) 428declare ptr @llvm.strip.invariant.group.p0(ptr) 429 430 431declare void @llvm.assume(i1 %cmp.vtables) 432 433 434!0 = !{} 435