Index: lib/Transforms/Scalar/EarlyCSE.cpp =================================================================== --- lib/Transforms/Scalar/EarlyCSE.cpp +++ lib/Transforms/Scalar/EarlyCSE.cpp @@ -562,6 +562,14 @@ continue; } + if (match(Inst, m_Intrinsic())) { + // invariant.start intrinsics read memory, but don't write any memory. + // Accordingly, don't update the generation but consume the last store (to + // avoid an incorrect DSE). + LastStore = nullptr; + continue; + } + if (match(Inst, m_Intrinsic())) { if (auto *CondI = dyn_cast(cast(Inst)->getArgOperand(0))) { Index: test/Transforms/EarlyCSE/invariant.start.ll =================================================================== --- /dev/null +++ test/Transforms/EarlyCSE/invariant.start.ll @@ -0,0 +1,53 @@ +; RUN: opt < %s -S -early-cse | FileCheck %s +; RUN: opt < %s -S -passes=early-cse | FileCheck %s + +declare {}* @llvm.invariant.start.p0i8(i64, i8* nocapture) nounwind readonly + +; Check that we do load-load forwarding over invariant.start, since it does not +; clobber memory +define i8 @test1(i8 *%P) { + ; CHECK-LABEL:@test1( + ; CHECK-NEXT: %V1 = load i8, i8* %P + ; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P) + ; CHECK-NEXT: ret i8 0 + + + %V1 = load i8, i8* %P + %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P) + %V2 = load i8, i8* %P + %Diff = sub i8 %V1, %V2 + ret i8 %Diff +} + + +; Trivial Store->load forwarding over invariant.start +define i8 @test2(i8 *%P) { + ; CHECK-LABEL: @test2( + ; CHECK-NEXT: store i8 42, i8* %P + ; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P) + ; CHECK-NEXT: ret i8 42 + + + store i8 42, i8* %P + %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P) + %V1 = load i8, i8* %P + ret i8 %V1 +} + +; Check that we do not DSE over invariant.start calls, since the first store to +; %P is valid, and the second store is actually unreachable based on semantics +; of invariant.start. Due to this, we treat invariant.start as _read_memory_, +; and the first store should not be DSE'd +define void @test3(i8* %P) { + +; CHECK-LABEL: @test3( +; CHECK-NEXT: store i8 50, i8* %P +; CHECK-NEXT: %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P) +; CHECK-NEXT: store i8 60, i8* %P + + + store i8 50, i8* %P + %i = call {}* @llvm.invariant.start.p0i8(i64 1, i8* %P) + store i8 60, i8* %P + ret void +}