diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3712,8 +3712,9 @@ return false; } // We can only sink load instructions if there is nothing between the load and - // the end of block that could change the value. - if (I->mayReadFromMemory()) { + // the end of block that could change the value. We do not need to do these + // checks if we have a call with noalias return attribute. + if (I->mayReadFromMemory() && !isNoAliasCall(I)) { // We don't want to do any sophisticated alias analysis, so we only check // the instructions after I in I's parent block if we try to sink to its // successor block. diff --git a/llvm/test/Transforms/InstCombine/sink_instruction.ll b/llvm/test/Transforms/InstCombine/sink_instruction.ll --- a/llvm/test/Transforms/InstCombine/sink_instruction.ll +++ b/llvm/test/Transforms/InstCombine/sink_instruction.ll @@ -242,12 +242,12 @@ ret void } -; TODO: We can sink down the allocation to its only use. +; We can sink down the allocation to its only use. define i8** @test_allocation_sink_bc(i1 %cond) { ; CHECK-LABEL: @test_allocation_sink_bc( -; CHECK-NEXT: [[A:%.*]] = call dereferenceable_or_null(16000) i8* @malloc(i32 16000) -; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] +; CHECK: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: +; CHECK-NEXT: [[A:%.*]] = call dereferenceable_or_null(16000) i8* @malloc(i32 16000) ; CHECK-NEXT: [[X:%.*]] = bitcast i8* [[A]] to i8** ; CHECK-NEXT: ret i8** [[X]] ; CHECK: else: @@ -269,12 +269,12 @@ ret i8** %Y } -; TODO: We can sink down the allocation to its only use. +; We can sink down the allocation to its only use. define void @test_allocation_sink(i1 %cond) { ; CHECK-LABEL: @test_allocation_sink( -; CHECK-NEXT: [[A:%.*]] = call dereferenceable_or_null(16000) i8* @malloc(i32 16000) -; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] +; CHECK: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: +; CHECK-NEXT: [[A:%.*]] = call dereferenceable_or_null(16000) i8* @malloc(i32 16000) ; CHECK-NEXT: call void @check(i8* [[A]]) ; CHECK-NEXT: ret void ; CHECK: else: @@ -291,15 +291,15 @@ ret void } -; TODO: We can sink this malloc as well down to the use block. +; We can sink this malloc as well down to the use block. define void @test_allocation_sink_noalias_load(i1 %cond, i32 %i, i32* readonly %P) { ; CHECK-LABEL: @test_allocation_sink_noalias_load( -; CHECK-NEXT: [[A:%.*]] = call dereferenceable_or_null(16000) i8* @malloc(i32 16000) -; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I:%.*]] to i64 +; CHECK: [[IDXPROM:%.*]] = sext i32 [[I:%.*]] to i64 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 [[IDXPROM]] ; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[ARRAYIDX]], align 4 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: +; CHECK-NEXT: [[A:%.*]] = call dereferenceable_or_null(16000) i8* @malloc(i32 16000) ; CHECK-NEXT: call void @check(i8* [[A]]) ; CHECK-NEXT: ret void ; CHECK: else: @@ -323,14 +323,14 @@ ret void } -; TODO: We can sink both allocations to its only use without them being +; We can sink both allocations to its only use without them being ; incorrectly reordered. define void @test_allocation_sink2(i1 %cond) { ; CHECK-LABEL: @test_allocation_sink2( +; CHECK: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] +; CHECK: if: ; CHECK-NEXT: [[A:%.*]] = call dereferenceable_or_null(16000) i8* @malloc(i32 16000) ; CHECK-NEXT: [[B:%.*]] = call dereferenceable_or_null(16) i8* @malloc(i32 16) -; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] -; CHECK: if: ; CHECK-NEXT: call void @check2(i8* [[A]], i8* [[B]]) ; CHECK-NEXT: ret void ; CHECK: else: