1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature 2; RUN: opt < %s -S -passes=early-cse -earlycse-debug-hash | FileCheck %s --check-prefixes=CHECK,NO_ASSUME 3; RUN: opt < %s -S -passes=early-cse --enable-knowledge-retention | FileCheck %s --check-prefixes=CHECK,USE_ASSUME 4; RUN: opt < %s -S -passes=early-cse | FileCheck %s --check-prefixes=CHECK,NO_ASSUME 5 6declare ptr @llvm.invariant.start.p0(i64, ptr nocapture) nounwind readonly 7declare void @llvm.invariant.end.p0(ptr, i64, ptr nocapture) nounwind 8 9; Check that we do load-load forwarding over invariant.start, since it does not 10; clobber memory 11define i8 @test_bypass1(ptr%P) { 12; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass1 13; NO_ASSUME-SAME: (ptr [[P:%.*]]) { 14; NO_ASSUME-NEXT: [[V1:%.*]] = load i8, ptr [[P]], align 1 15; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 16; NO_ASSUME-NEXT: ret i8 0 17; 18; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass1 19; USE_ASSUME-SAME: (ptr [[P:%.*]]) { 20; USE_ASSUME-NEXT: [[V1:%.*]] = load i8, ptr [[P]], align 1 21; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 22; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 1), "nonnull"(ptr [[P]]) ] 23; USE_ASSUME-NEXT: ret i8 0 24; 25 26 %V1 = load i8, ptr %P 27 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P) 28 %V2 = load i8, ptr %P 29 %Diff = sub i8 %V1, %V2 30 ret i8 %Diff 31} 32 33 34; Trivial Store->load forwarding over invariant.start 35define i8 @test_bypass2(ptr%P) { 36; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass2 37; NO_ASSUME-SAME: (ptr [[P:%.*]]) { 38; NO_ASSUME-NEXT: store i8 42, ptr [[P]], align 1 39; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 40; NO_ASSUME-NEXT: ret i8 42 41; 42; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass2 43; USE_ASSUME-SAME: (ptr [[P:%.*]]) { 44; USE_ASSUME-NEXT: store i8 42, ptr [[P]], align 1 45; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 46; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 1), "nonnull"(ptr [[P]]) ] 47; USE_ASSUME-NEXT: ret i8 42 48; 49 50 store i8 42, ptr %P 51 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P) 52 %V1 = load i8, ptr %P 53 ret i8 %V1 54} 55 56define i8 @test_bypass_store_load(ptr%P, ptr%P2) { 57; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass_store_load 58; NO_ASSUME-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) { 59; NO_ASSUME-NEXT: store i8 42, ptr [[P]], align 1 60; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 61; NO_ASSUME-NEXT: store i8 0, ptr [[P2]], align 1 62; NO_ASSUME-NEXT: ret i8 42 63; 64; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass_store_load 65; USE_ASSUME-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) { 66; USE_ASSUME-NEXT: store i8 42, ptr [[P]], align 1 67; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 68; USE_ASSUME-NEXT: store i8 0, ptr [[P2]], align 1 69; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 1), "nonnull"(ptr [[P]]) ] 70; USE_ASSUME-NEXT: ret i8 42 71; 72 73 store i8 42, ptr %P 74 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P) 75 store i8 0, ptr %P2 76 %V1 = load i8, ptr %P 77 ret i8 %V1 78} 79 80define i8 @test_bypass_store_load_aatags_1(ptr%P, ptr%P2) { 81; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass_store_load_aatags_1 82; NO_ASSUME-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) { 83; NO_ASSUME-NEXT: store i8 42, ptr [[P]], align 1, !tbaa [[TBAA0:![0-9]+]] 84; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 85; NO_ASSUME-NEXT: store i8 0, ptr [[P2]], align 1 86; NO_ASSUME-NEXT: ret i8 42 87; 88; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass_store_load_aatags_1 89; USE_ASSUME-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) { 90; USE_ASSUME-NEXT: store i8 42, ptr [[P]], align 1, !tbaa [[TBAA0:![0-9]+]] 91; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 92; USE_ASSUME-NEXT: store i8 0, ptr [[P2]], align 1 93; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 1), "nonnull"(ptr [[P]]) ] 94; USE_ASSUME-NEXT: ret i8 42 95; 96 97 store i8 42, ptr %P, !tbaa !0 98 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P) 99 store i8 0, ptr %P2 100 %V1 = load i8, ptr %P 101 ret i8 %V1 102} 103 104; The test demonstrates a missed optimization opportunity in case when the load 105; has AA tags that are different from the store tags. 106define i8 @test_bypass_store_load_aatags_2(ptr%P, ptr%P2) { 107; CHECK-LABEL: define {{[^@]+}}@test_bypass_store_load_aatags_2 108; CHECK-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) { 109; CHECK-NEXT: store i8 42, ptr [[P]], align 1 110; CHECK-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 111; CHECK-NEXT: store i8 0, ptr [[P2]], align 1 112; CHECK-NEXT: [[V1:%.*]] = load i8, ptr [[P]], align 1, !tbaa [[TBAA0:![0-9]+]] 113; CHECK-NEXT: ret i8 [[V1]] 114; 115 116 store i8 42, ptr %P 117 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P) 118 store i8 0, ptr %P2 119 %V1 = load i8, ptr %P, !tbaa !0 120 ret i8 %V1 121} 122 123; We can DSE over invariant.start calls, since the first store to 124; %P is valid, and the second store is actually unreachable based on semantics 125; of invariant.start. 126define void @test_bypass3(ptr %P) { 127; NO_ASSUME-LABEL: define {{[^@]+}}@test_bypass3 128; NO_ASSUME-SAME: (ptr [[P:%.*]]) { 129; NO_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 130; NO_ASSUME-NEXT: store i8 60, ptr [[P]], align 1 131; NO_ASSUME-NEXT: ret void 132; 133; USE_ASSUME-LABEL: define {{[^@]+}}@test_bypass3 134; USE_ASSUME-SAME: (ptr [[P:%.*]]) { 135; USE_ASSUME-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 136; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 1), "nonnull"(ptr [[P]]) ] 137; USE_ASSUME-NEXT: store i8 60, ptr [[P]], align 1 138; USE_ASSUME-NEXT: ret void 139; 140 141 store i8 50, ptr %P 142 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P) 143 store i8 60, ptr %P 144 ret void 145} 146 147 148; FIXME: Now the first store can actually be eliminated, since there is no read within 149; the invariant region, between start and end. 150define void @test_bypass4(ptr %P) { 151; CHECK-LABEL: define {{[^@]+}}@test_bypass4 152; CHECK-SAME: (ptr [[P:%.*]]) { 153; CHECK-NEXT: store i8 50, ptr [[P]], align 1 154; CHECK-NEXT: [[I:%.*]] = call ptr @llvm.invariant.start.p0(i64 1, ptr [[P]]) 155; CHECK-NEXT: call void @llvm.invariant.end.p0(ptr [[I]], i64 1, ptr [[P]]) 156; CHECK-NEXT: store i8 60, ptr [[P]], align 1 157; CHECK-NEXT: ret void 158; 159 160 161 store i8 50, ptr %P 162 %i = call ptr @llvm.invariant.start.p0(i64 1, ptr %P) 163 call void @llvm.invariant.end.p0(ptr %i, i64 1, ptr %P) 164 store i8 60, ptr %P 165 ret void 166} 167 168 169declare void @clobber() 170 171define i32 @test_before_load(ptr %p) { 172; NO_ASSUME-LABEL: define {{[^@]+}}@test_before_load 173; NO_ASSUME-SAME: (ptr [[P:%.*]]) { 174; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 175; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 176; NO_ASSUME-NEXT: call void @clobber() 177; NO_ASSUME-NEXT: ret i32 0 178; 179; USE_ASSUME-LABEL: define {{[^@]+}}@test_before_load 180; USE_ASSUME-SAME: (ptr [[P:%.*]]) { 181; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 182; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 183; USE_ASSUME-NEXT: call void @clobber() 184; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ] 185; USE_ASSUME-NEXT: ret i32 0 186; 187 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 188 %v1 = load i32, ptr %p 189 call void @clobber() 190 %v2 = load i32, ptr %p 191 %sub = sub i32 %v1, %v2 192 ret i32 %sub 193} 194 195define i32 @test_before_clobber(ptr %p) { 196; NO_ASSUME-LABEL: define {{[^@]+}}@test_before_clobber 197; NO_ASSUME-SAME: (ptr [[P:%.*]]) { 198; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 199; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 200; NO_ASSUME-NEXT: call void @clobber() 201; NO_ASSUME-NEXT: ret i32 0 202; 203; USE_ASSUME-LABEL: define {{[^@]+}}@test_before_clobber 204; USE_ASSUME-SAME: (ptr [[P:%.*]]) { 205; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 206; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 207; USE_ASSUME-NEXT: call void @clobber() 208; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ] 209; USE_ASSUME-NEXT: ret i32 0 210; 211 %v1 = load i32, ptr %p 212 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 213 call void @clobber() 214 %v2 = load i32, ptr %p 215 %sub = sub i32 %v1, %v2 216 ret i32 %sub 217} 218 219define i32 @test_duplicate_scope(ptr %p) { 220; NO_ASSUME-LABEL: define {{[^@]+}}@test_duplicate_scope 221; NO_ASSUME-SAME: (ptr [[P:%.*]]) { 222; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 223; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 224; NO_ASSUME-NEXT: call void @clobber() 225; NO_ASSUME-NEXT: [[TMP2:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 226; NO_ASSUME-NEXT: ret i32 0 227; 228; USE_ASSUME-LABEL: define {{[^@]+}}@test_duplicate_scope 229; USE_ASSUME-SAME: (ptr [[P:%.*]]) { 230; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 231; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 232; USE_ASSUME-NEXT: call void @clobber() 233; USE_ASSUME-NEXT: [[TMP2:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 234; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ] 235; USE_ASSUME-NEXT: ret i32 0 236; 237 %v1 = load i32, ptr %p 238 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 239 call void @clobber() 240 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 241 %v2 = load i32, ptr %p 242 %sub = sub i32 %v1, %v2 243 ret i32 %sub 244} 245 246define i32 @test_unanalzyable_load(ptr %p) { 247; NO_ASSUME-LABEL: define {{[^@]+}}@test_unanalzyable_load 248; NO_ASSUME-SAME: (ptr [[P:%.*]]) { 249; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 250; NO_ASSUME-NEXT: call void @clobber() 251; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 252; NO_ASSUME-NEXT: call void @clobber() 253; NO_ASSUME-NEXT: ret i32 0 254; 255; USE_ASSUME-LABEL: define {{[^@]+}}@test_unanalzyable_load 256; USE_ASSUME-SAME: (ptr [[P:%.*]]) { 257; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 258; USE_ASSUME-NEXT: call void @clobber() 259; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 260; USE_ASSUME-NEXT: call void @clobber() 261; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ] 262; USE_ASSUME-NEXT: ret i32 0 263; 264 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 265 call void @clobber() 266 %v1 = load i32, ptr %p 267 call void @clobber() 268 %v2 = load i32, ptr %p 269 %sub = sub i32 %v1, %v2 270 ret i32 %sub 271} 272 273define i32 @test_negative_after_clobber(ptr %p) { 274; CHECK-LABEL: define {{[^@]+}}@test_negative_after_clobber 275; CHECK-SAME: (ptr [[P:%.*]]) { 276; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 277; CHECK-NEXT: call void @clobber() 278; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 279; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4 280; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]] 281; CHECK-NEXT: ret i32 [[SUB]] 282; 283 %v1 = load i32, ptr %p 284 call void @clobber() 285 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 286 %v2 = load i32, ptr %p 287 %sub = sub i32 %v1, %v2 288 ret i32 %sub 289} 290 291define i32 @test_merge(ptr %p, i1 %cnd) { 292; NO_ASSUME-LABEL: define {{[^@]+}}@test_merge 293; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) { 294; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 295; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 296; NO_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]] 297; NO_ASSUME: taken: 298; NO_ASSUME-NEXT: call void @clobber() 299; NO_ASSUME-NEXT: br label [[MERGE]] 300; NO_ASSUME: merge: 301; NO_ASSUME-NEXT: ret i32 0 302; 303; USE_ASSUME-LABEL: define {{[^@]+}}@test_merge 304; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) { 305; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 306; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 307; USE_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]] 308; USE_ASSUME: taken: 309; USE_ASSUME-NEXT: call void @clobber() 310; USE_ASSUME-NEXT: br label [[MERGE]] 311; USE_ASSUME: merge: 312; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ] 313; USE_ASSUME-NEXT: ret i32 0 314; 315 %v1 = load i32, ptr %p 316 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 317 br i1 %cnd, label %merge, label %taken 318 319taken: 320 call void @clobber() 321 br label %merge 322merge: 323 %v2 = load i32, ptr %p 324 %sub = sub i32 %v1, %v2 325 ret i32 %sub 326} 327 328define i32 @test_negative_after_mergeclobber(ptr %p, i1 %cnd) { 329; CHECK-LABEL: define {{[^@]+}}@test_negative_after_mergeclobber 330; CHECK-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) { 331; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 332; CHECK-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]] 333; CHECK: taken: 334; CHECK-NEXT: call void @clobber() 335; CHECK-NEXT: br label [[MERGE]] 336; CHECK: merge: 337; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 338; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4 339; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]] 340; CHECK-NEXT: ret i32 [[SUB]] 341; 342 %v1 = load i32, ptr %p 343 br i1 %cnd, label %merge, label %taken 344 345taken: 346 call void @clobber() 347 br label %merge 348merge: 349 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 350 %v2 = load i32, ptr %p 351 %sub = sub i32 %v1, %v2 352 ret i32 %sub 353} 354 355; In theory, this version could work, but earlycse is incapable of 356; merging facts along distinct paths. 357define i32 @test_false_negative_merge(ptr %p, i1 %cnd) { 358; CHECK-LABEL: define {{[^@]+}}@test_false_negative_merge 359; CHECK-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) { 360; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 361; CHECK-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]] 362; CHECK: taken: 363; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 364; CHECK-NEXT: call void @clobber() 365; CHECK-NEXT: br label [[MERGE]] 366; CHECK: merge: 367; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4 368; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]] 369; CHECK-NEXT: ret i32 [[SUB]] 370; 371 %v1 = load i32, ptr %p 372 br i1 %cnd, label %merge, label %taken 373 374taken: 375 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 376 call void @clobber() 377 br label %merge 378merge: 379 %v2 = load i32, ptr %p 380 %sub = sub i32 %v1, %v2 381 ret i32 %sub 382} 383 384define i32 @test_merge_unanalyzable_load(ptr %p, i1 %cnd) { 385; NO_ASSUME-LABEL: define {{[^@]+}}@test_merge_unanalyzable_load 386; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) { 387; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 388; NO_ASSUME-NEXT: call void @clobber() 389; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 390; NO_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]] 391; NO_ASSUME: taken: 392; NO_ASSUME-NEXT: call void @clobber() 393; NO_ASSUME-NEXT: br label [[MERGE]] 394; NO_ASSUME: merge: 395; NO_ASSUME-NEXT: ret i32 0 396; 397; USE_ASSUME-LABEL: define {{[^@]+}}@test_merge_unanalyzable_load 398; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) { 399; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 400; USE_ASSUME-NEXT: call void @clobber() 401; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 402; USE_ASSUME-NEXT: br i1 [[CND]], label [[MERGE:%.*]], label [[TAKEN:%.*]] 403; USE_ASSUME: taken: 404; USE_ASSUME-NEXT: call void @clobber() 405; USE_ASSUME-NEXT: br label [[MERGE]] 406; USE_ASSUME: merge: 407; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ] 408; USE_ASSUME-NEXT: ret i32 0 409; 410 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 411 call void @clobber() 412 %v1 = load i32, ptr %p 413 br i1 %cnd, label %merge, label %taken 414 415taken: 416 call void @clobber() 417 br label %merge 418merge: 419 %v2 = load i32, ptr %p 420 %sub = sub i32 %v1, %v2 421 ret i32 %sub 422} 423 424define void @test_dse_before_load(ptr %p, i1 %cnd) { 425; NO_ASSUME-LABEL: define {{[^@]+}}@test_dse_before_load 426; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) { 427; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 428; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 429; NO_ASSUME-NEXT: call void @clobber() 430; NO_ASSUME-NEXT: ret void 431; 432; USE_ASSUME-LABEL: define {{[^@]+}}@test_dse_before_load 433; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) { 434; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 435; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 436; USE_ASSUME-NEXT: call void @clobber() 437; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ] 438; USE_ASSUME-NEXT: ret void 439; 440 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 441 %v1 = load i32, ptr %p 442 call void @clobber() 443 store i32 %v1, ptr %p 444 ret void 445} 446 447define void @test_dse_after_load(ptr %p, i1 %cnd) { 448; NO_ASSUME-LABEL: define {{[^@]+}}@test_dse_after_load 449; NO_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) { 450; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 451; NO_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 452; NO_ASSUME-NEXT: call void @clobber() 453; NO_ASSUME-NEXT: ret void 454; 455; USE_ASSUME-LABEL: define {{[^@]+}}@test_dse_after_load 456; USE_ASSUME-SAME: (ptr [[P:%.*]], i1 [[CND:%.*]]) { 457; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 458; USE_ASSUME-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 459; USE_ASSUME-NEXT: call void @clobber() 460; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ] 461; USE_ASSUME-NEXT: ret void 462; 463 %v1 = load i32, ptr %p 464 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 465 call void @clobber() 466 store i32 %v1, ptr %p 467 ret void 468} 469 470 471; In this case, we have a false negative since MemoryLocation is implicitly 472; typed due to the user of a Value to represent the address. Note that other 473; passes will canonicalize away the bitcasts in this example. 474define i32 @test_false_negative_types(ptr %p) { 475; CHECK-LABEL: define {{[^@]+}}@test_false_negative_types 476; CHECK-SAME: (ptr [[P:%.*]]) { 477; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 478; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 479; CHECK-NEXT: call void @clobber() 480; CHECK-NEXT: [[V2F:%.*]] = load float, ptr [[P]], align 4 481; CHECK-NEXT: [[V2:%.*]] = bitcast float [[V2F]] to i32 482; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]] 483; CHECK-NEXT: ret i32 [[SUB]] 484; 485 call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 486 %v1 = load i32, ptr %p 487 call void @clobber() 488 %v2f = load float, ptr %p 489 %v2 = bitcast float %v2f to i32 490 %sub = sub i32 %v1, %v2 491 ret i32 %sub 492} 493 494define i32 @test_negative_size1(ptr %p) { 495; CHECK-LABEL: define {{[^@]+}}@test_negative_size1 496; CHECK-SAME: (ptr [[P:%.*]]) { 497; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 3, ptr [[P]]) 498; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 499; CHECK-NEXT: call void @clobber() 500; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4 501; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]] 502; CHECK-NEXT: ret i32 [[SUB]] 503; 504 call ptr @llvm.invariant.start.p0(i64 3, ptr %p) 505 %v1 = load i32, ptr %p 506 call void @clobber() 507 %v2 = load i32, ptr %p 508 %sub = sub i32 %v1, %v2 509 ret i32 %sub 510} 511 512define i32 @test_negative_size2(ptr %p) { 513; CHECK-LABEL: define {{[^@]+}}@test_negative_size2 514; CHECK-SAME: (ptr [[P:%.*]]) { 515; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.invariant.start.p0(i64 0, ptr [[P]]) 516; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 517; CHECK-NEXT: call void @clobber() 518; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4 519; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]] 520; CHECK-NEXT: ret i32 [[SUB]] 521; 522 call ptr @llvm.invariant.start.p0(i64 0, ptr %p) 523 %v1 = load i32, ptr %p 524 call void @clobber() 525 %v2 = load i32, ptr %p 526 %sub = sub i32 %v1, %v2 527 ret i32 %sub 528} 529 530define i32 @test_negative_scope(ptr %p) { 531; CHECK-LABEL: define {{[^@]+}}@test_negative_scope 532; CHECK-SAME: (ptr [[P:%.*]]) { 533; CHECK-NEXT: [[SCOPE:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 534; CHECK-NEXT: call void @llvm.invariant.end.p0(ptr [[SCOPE]], i64 4, ptr [[P]]) 535; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 536; CHECK-NEXT: call void @clobber() 537; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4 538; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]] 539; CHECK-NEXT: ret i32 [[SUB]] 540; 541 %scope = call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 542 call void @llvm.invariant.end.p0(ptr %scope, i64 4, ptr %p) 543 %v1 = load i32, ptr %p 544 call void @clobber() 545 %v2 = load i32, ptr %p 546 %sub = sub i32 %v1, %v2 547 ret i32 %sub 548} 549 550define i32 @test_false_negative_scope(ptr %p) { 551; CHECK-LABEL: define {{[^@]+}}@test_false_negative_scope 552; CHECK-SAME: (ptr [[P:%.*]]) { 553; CHECK-NEXT: [[SCOPE:%.*]] = call ptr @llvm.invariant.start.p0(i64 4, ptr [[P]]) 554; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4 555; CHECK-NEXT: call void @clobber() 556; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[P]], align 4 557; CHECK-NEXT: call void @llvm.invariant.end.p0(ptr [[SCOPE]], i64 4, ptr [[P]]) 558; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[V1]], [[V2]] 559; CHECK-NEXT: ret i32 [[SUB]] 560; 561 %scope = call ptr @llvm.invariant.start.p0(i64 4, ptr %p) 562 %v1 = load i32, ptr %p 563 call void @clobber() 564 %v2 = load i32, ptr %p 565 call void @llvm.invariant.end.p0(ptr %scope, i64 4, ptr %p) 566 %sub = sub i32 %v1, %v2 567 ret i32 %sub 568} 569 570; Invariant load defact starts an invariant.start scope of the appropriate size 571define i32 @test_invariant_load_scope(ptr %p) { 572; NO_ASSUME-LABEL: define {{[^@]+}}@test_invariant_load_scope 573; NO_ASSUME-SAME: (ptr [[P:%.*]]) { 574; NO_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4, !invariant.load !4 575; NO_ASSUME-NEXT: call void @clobber() 576; NO_ASSUME-NEXT: ret i32 0 577; 578; USE_ASSUME-LABEL: define {{[^@]+}}@test_invariant_load_scope 579; USE_ASSUME-SAME: (ptr [[P:%.*]]) { 580; USE_ASSUME-NEXT: [[V1:%.*]] = load i32, ptr [[P]], align 4, !invariant.load !4 581; USE_ASSUME-NEXT: call void @clobber() 582; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 4), "nonnull"(ptr [[P]]), "align"(ptr [[P]], i64 4) ] 583; USE_ASSUME-NEXT: ret i32 0 584; 585 %v1 = load i32, ptr %p, !invariant.load !{} 586 call void @clobber() 587 %v2 = load i32, ptr %p 588 %sub = sub i32 %v1, %v2 589 ret i32 %sub 590} 591 592; USE_ASSUME: declare void @llvm.assume(i1 noundef) 593 594!0 = !{!1, !1, i64 0} 595!1 = !{!"float", !2, i64 0} 596!2 = !{!"omnipotent char", !3, i64 0} 597!3 = !{!"Simple C/C++ TBAA"} 598