Index: lib/Transforms/Scalar/EarlyCSE.cpp =================================================================== --- lib/Transforms/Scalar/EarlyCSE.cpp +++ lib/Transforms/Scalar/EarlyCSE.cpp @@ -271,8 +271,11 @@ return false; CallInst *CI = dyn_cast(Inst); - if (!CI || !CI->onlyReadsMemory()) + + // Handle readnone, readonly and writeonly. + if (!CI || !(CI->doesNotReadMemory() || CI->onlyReadsMemory())) return false; + return true; } }; @@ -996,7 +999,7 @@ !(MemInst.isValid() && !MemInst.mayReadFromMemory())) LastStore = nullptr; - // If this is a read-only call, process it. + // If this is a read-only or writeonly call, process it. if (CallValue::canHandle(Inst)) { // If we have an available version of this call, and if it is the right // generation, replace this instruction. @@ -1010,6 +1013,13 @@ LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n"); continue; } + // When handling writeonly function calls we need to update lastStore + // and currentGen. + auto *CI = dyn_cast(Inst); + if (CI && CI->doesNotReadMemory() && !CI->doesNotAccessMemory()) { + ++CurrentGeneration; + LastStore = nullptr; + } if (!Inst->use_empty()) Inst->replaceAllUsesWith(InVal.first); removeMSSA(Inst); @@ -1018,10 +1028,18 @@ ++NumCSECall; continue; } - // Otherwise, remember that we have this instruction. AvailableCalls.insert( Inst, std::pair(Inst, CurrentGeneration)); + + // When handling writeonly function calls we need to update lastStore + // and currentGen. + auto *CI = dyn_cast(Inst); + if (CI && CI->doesNotReadMemory() && !CI->doesNotAccessMemory()) { + ++CurrentGeneration; + LastStore = nullptr; + } + continue; } Index: test/Transforms/EarlyCSE/memoryssa.ll =================================================================== --- test/Transforms/EarlyCSE/memoryssa.ll +++ test/Transforms/EarlyCSE/memoryssa.ll @@ -106,3 +106,34 @@ store i32 %v2, i32* @G3 ret void } + +;; Check that writeonly call gets CSE'd when using MSSA +declare i32 @write_only() writeonly + +define void @test_write_only(i1 %c, i32* %p) { +; CHECK-LABEL: entry: +; CHECK-NOMEMSSA-LABEL: entry: +entry: +; CHECK: call i32 @write_only() +; CHECK-NOMEMSSA: call i32 @write_only() + %call = call i32 @write_only() +; CHECK: %v1 = load i32, i32* @G1 +; CHECK-NOMEMSSA: %v1 = load i32, i32* @G1 + %v1 = load i32, i32* @G1 +; CHECK-NOT: call i32 @write_only() +; CHECK-NOMEMSSA: call i32 @write_only() + %call2 = call i32 @write_only() +; CHECK: store +; CHECK-NOMEMSSA: store + store i32 %v1, i32* @G2 +; CHECK: call i32 @write_only() +; CHECK-NOMEMSSA: call i32 @write_only() + %call3 = call i32 @write_only() +; CHECK: store +; CHECK-NOMEMSSA: store + store i32 %v1, i32* @G2 +; CHECK: call i32 @write_only() +; CHECK-NOMEMSSA: call i32 @write_only() + %call4 = call i32 @write_only() + ret void +}