Index: llvm/trunk/lib/Transforms/Scalar/LICM.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LICM.cpp +++ llvm/trunk/lib/Transforms/Scalar/LICM.cpp @@ -471,6 +471,17 @@ if (Behavior == FMRB_DoesNotAccessMemory) return true; if (AliasAnalysis::onlyReadsMemory(Behavior)) { + // A readonly argmemonly function only reads from memory pointed to by + // it's arguments with arbitrary offsets. If we can prove there are no + // writes to this memory in the loop, we can hoist or sink. + if (AliasAnalysis::onlyAccessesArgPointees(Behavior)) { + for (Value *Op : CI->arg_operands()) + if (Op->getType()->isPointerTy() && + pointerInvalidatedByLoop(Op, MemoryLocation::UnknownSize, + AAMDNodes(), CurAST)) + return false; + return true; + } // If this call only reads from memory and there are no writes to memory // in the loop, we can hoist or sink the call as appropriate. bool FoundMod = false; Index: llvm/trunk/test/Transforms/LICM/argmemonly-call.ll =================================================================== --- llvm/trunk/test/Transforms/LICM/argmemonly-call.ll +++ llvm/trunk/test/Transforms/LICM/argmemonly-call.ll @@ -0,0 +1,69 @@ +; RUN: opt -S -basicaa -licm %s | FileCheck %s +declare i32 @foo() readonly argmemonly nounwind +declare i32 @foo2() readonly nounwind +declare i32 @bar(i32* %loc2) readonly argmemonly nounwind + +define void @test(i32* %loc) { +; CHECK-LABEL: @test +; CHECK: @foo +; CHECK-LABEL: loop: + br label %loop + +loop: + %res = call i32 @foo() + store i32 %res, i32* %loc + br label %loop +} + +; Negative test: show argmemonly is required +define void @test_neg(i32* %loc) { +; CHECK-LABEL: @test_neg +; CHECK-LABEL: loop: +; CHECK: @foo + br label %loop + +loop: + %res = call i32 @foo2() + store i32 %res, i32* %loc + br label %loop +} + +define void @test2(i32* noalias %loc, i32* noalias %loc2) { +; CHECK-LABEL: @test2 +; CHECK: @bar +; CHECK-LABEL: loop: + br label %loop + +loop: + %res = call i32 @bar(i32* %loc2) + store i32 %res, i32* %loc + br label %loop +} + +; Negative test: %might clobber gep +define void @test3(i32* %loc) { +; CHECK-LABEL: @test3 +; CHECK-LABEL: loop: +; CHECK: @bar + br label %loop + +loop: + %res = call i32 @bar(i32* %loc) + %gep = getelementptr i32, i32 *%loc, i64 1000000 + store i32 %res, i32* %gep + br label %loop +} + + +; Negative test: %loc might alias %loc2 +define void @test4(i32* %loc, i32* %loc2) { +; CHECK-LABEL: @test4 +; CHECK-LABEL: loop: +; CHECK: @bar + br label %loop + +loop: + %res = call i32 @bar(i32* %loc2) + store i32 %res, i32* %loc + br label %loop +}