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