diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -1172,11 +1172,12 @@ // Handle simple cases by querying alias analysis. FunctionModRefBehavior Behavior = AA->getModRefBehavior(CI); - if (Behavior == FMRB_DoesNotAccessMemory) + if (AliasAnalysis::doesNotReadMemory(Behavior)) { + // A readnone/writeonly function can be moved. return true; - if (AliasAnalysis::onlyReadsMemory(Behavior)) { + } else 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 + // its 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)) { // TODO: expand to writeable arguments @@ -2012,7 +2013,7 @@ // Note that proving a load safe to speculate requires proving // sufficient alignment at the target location. Proving it guaranteed // to execute does as well. Thus we can increase our guaranteed - // alignment as well. + // alignment as well. if (!DereferenceableInPH || (InstAlignment > Alignment)) if (isSafeToExecuteUnconditionally(*Load, DT, CurLoop, SafetyInfo, ORE, Preheader->getTerminator())) { diff --git a/llvm/test/Transforms/LICM/hoist-attributes.ll b/llvm/test/Transforms/LICM/hoist-attributes.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LICM/hoist-attributes.ll @@ -0,0 +1,73 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S < %s -licm | FileCheck %s + +declare i32 @foo1a() readnone nounwind +declare i32 @foo1b(i8* readnone) readnone nounwind +declare i32 @foo1c(i8* readnone) nounwind + +declare void @foo2a() writeonly nounwind +declare void @foo2b(i8* writeonly) writeonly nounwind +declare void @foo2c(i8* writeonly) nounwind + +@str = internal global [4 x i8] c"foo\00", align 1 + +; Functions that are nounwind and readnone (foo1a, foo1b) can be hoisted +define i32 @test1(i1 %c) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[STR:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @str, i64 0, i64 0 +; CHECK-NEXT: [[RET1A:%.*]] = call i32 @foo1a() +; CHECK-NEXT: [[RET1B:%.*]] = call i32 @foo1b(i8* [[STR]]) +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ADD1C:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[ADD1A:%.*]] = add nuw i32 [[SUM]], [[RET1A]] +; CHECK-NEXT: [[ADD1B:%.*]] = add nuw i32 [[ADD1A]], [[RET1B]] +; CHECK-NEXT: [[RET1C:%.*]] = call i32 @foo1c(i8* [[STR]]) +; CHECK-NEXT: [[ADD1C]] = add nuw i32 [[ADD1B]], [[RET1C]] +; CHECK-NEXT: br i1 [[C:%.*]], label [[LOOP]], label [[OUT:%.*]] +; CHECK: out: +; CHECK-NEXT: [[ADD1C_LCSSA:%.*]] = phi i32 [ [[ADD1C]], [[LOOP]] ] +; CHECK-NEXT: ret i32 [[ADD1C_LCSSA]] +; +entry: + %str = getelementptr inbounds [4 x i8], [4 x i8]* @str, i64 0, i64 0 + br label %loop +loop: + %sum = phi i32 [ 0, %entry ], [ %add1c, %loop ] + %ret1a = call i32 @foo1a() + %add1a = add nuw i32 %sum, %ret1a + %ret1b = call i32 @foo1b(i8* %str) + %add1b = add nuw i32 %add1a, %ret1b + %ret1c = call i32 @foo1c(i8* %str) + %add1c = add nuw i32 %add1b, %ret1c + br i1 %c, label %loop, label %out +out: + ret i32 %add1c +} + +; Functions that are nounwind and writeonly (foo2a, foo2b) can be hoisted +define void @test2(i1 %c) { +; CHECK-LABEL: @test2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[STR:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @str, i64 0, i64 0 +; CHECK-NEXT: call void @foo2a() +; CHECK-NEXT: call void @foo2b(i8* [[STR]]) +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: call void @foo2c(i8* [[STR]]) +; CHECK-NEXT: br i1 [[C:%.*]], label [[LOOP]], label [[OUT:%.*]] +; CHECK: out: +; CHECK-NEXT: ret void +; +entry: + %str = getelementptr inbounds [4 x i8], [4 x i8]* @str, i64 0, i64 0 + br label %loop +loop: + call void @foo2a() + call void @foo2b(i8* %str) + call void @foo2c(i8* %str) + br i1 %c, label %loop, label %out +out: + ret void +}