Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3742,6 +3742,41 @@ return MadeIRChange; } +// Track the scopes used by !alias.scope. +// @llvm.experimental.noalias.scope.decl that declare a scope that is not used +// by a !alias.scope can be omitted. +class AliasScopeTracker { + SmallPtrSet UsedAliasScopes; + +public: + void analyse(Instruction *I) { + if (auto *MD = I->getMetadata(LLVMContext::MD_alias_scope)) + for (auto &MDOperand : cast(MD)->operands()) + if (auto *MDScope = dyn_cast(MDOperand)) + UsedAliasScopes.insert(MDScope); + } + + bool isNoAliasScopeDeclDead(Instruction *Inst) { + auto *II = dyn_cast(Inst); + if (!II || + II->getIntrinsicID() != Intrinsic::experimental_noalias_scope_decl) + return false; + + assert(II->use_empty() && "llvm.experimental.noalias.scope.decl in use ?"); + auto *MV = cast( + II->getOperand(Intrinsic::NoAliasScopeDeclScopeArg)); + const MDNode *MD = cast(MV->getMetadata()); + assert(MD->getNumOperands() == 1 && + "llvm.experimental.noalias.scope should refer to a single scope"); + auto &MDOperand = MD->getOperand(0); + if (auto *MD = dyn_cast(MDOperand)) + return !UsedAliasScopes.contains(MD); + + // Not an MDNode ? throw away. + return true; + } +}; + /// Populate the IC worklist from a function, by walking it in depth-first /// order and adding all reachable code to the worklist. /// @@ -3760,6 +3795,7 @@ SmallVector InstrsForInstCombineWorklist; DenseMap FoldedConstants; + AliasScopeTracker SeenAliasScopes; do { BasicBlock *BB = Worklist.pop_back_val(); @@ -3808,6 +3844,8 @@ // consumes non-trivial amount of time and provides no value for the optimization. if (!isa(Inst)) InstrsForInstCombineWorklist.push_back(Inst); + + SeenAliasScopes.analyse(Inst); } // Recursively visit successors. If this is a branch or switch on a @@ -3855,7 +3893,8 @@ for (Instruction *Inst : reverse(InstrsForInstCombineWorklist)) { // DCE instruction if trivially dead. As we iterate in reverse program // order here, we will clean up whole chains of dead instructions. - if (isInstructionTriviallyDead(Inst, TLI)) { + if (isInstructionTriviallyDead(Inst, TLI) || + SeenAliasScopes.isNoAliasScopeDeclDead(Inst)) { ++NumDeadInst; LLVM_DEBUG(dbgs() << "IC: DCE: " << *Inst << '\n'); salvageDebugInfo(*Inst); Index: llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll =================================================================== --- llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll +++ llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll @@ -68,9 +68,7 @@ ; CHECK: [[BUFFER:%.*]] = alloca [8 x i8], align 4 ; CHECK: [[SLOT:%.*]] = bitcast [8 x i8]* [[BUFFER]] to i32* ; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: store i32 7, i32* [[SLOT]], align 4 -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 7) ; CHECK-NEXT: ret i32 0 Index: llvm/test/Transforms/Coroutines/coro-retcon-value.ll =================================================================== --- llvm/test/Transforms/Coroutines/coro-retcon-value.ll +++ llvm/test/Transforms/Coroutines/coro-retcon-value.ll @@ -89,7 +89,6 @@ ; CHECK-NEXT: [[INC:%.*]] = add i32 [[LOAD]], 1 ; CHECK-NEXT: store i32 [[INC]], i32* [[SLOT]], align 4 ; CHECK-NEXT: call void @print(i32 [[INC]]) -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: ret i32 0 declare token @llvm.coro.id.retcon(i32, i32, i8*, i8*, i8*, i8*) Index: llvm/test/Transforms/Coroutines/coro-retcon.ll =================================================================== --- llvm/test/Transforms/Coroutines/coro-retcon.ll +++ llvm/test/Transforms/Coroutines/coro-retcon.ll @@ -78,7 +78,6 @@ ; CHECK-NEXT: [[LOAD:%.*]] = load i32, i32* [[SLOT]], align 4 ; CHECK-NEXT: [[INC:%.*]] = add i32 [[LOAD]], 1 ; CHECK-NEXT: call void @print(i32 [[INC]]) -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: ret i32 0 define hidden { i8*, i8* } @g(i8* %buffer, i16* %ptr) { Index: llvm/test/Transforms/Coroutines/ex2.ll =================================================================== --- llvm/test/Transforms/Coroutines/ex2.ll +++ llvm/test/Transforms/Coroutines/ex2.ll @@ -49,9 +49,7 @@ ret i32 0 ; CHECK-NOT: call i8* @CustomAlloc ; CHECK: call void @print(i32 4) -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 5) -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 6) ; CHECK-NEXT: ret i32 0 } Index: llvm/test/Transforms/Coroutines/ex3.ll =================================================================== --- llvm/test/Transforms/Coroutines/ex3.ll +++ llvm/test/Transforms/Coroutines/ex3.ll @@ -53,9 +53,7 @@ ret i32 0 ; CHECK-NOT: i8* @malloc ; CHECK: call void @print(i32 4) -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 -5) -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 5) ; CHECK: ret i32 0 } Index: llvm/test/Transforms/Coroutines/ex4.ll =================================================================== --- llvm/test/Transforms/Coroutines/ex4.ll +++ llvm/test/Transforms/Coroutines/ex4.ll @@ -50,9 +50,7 @@ call void @llvm.coro.destroy(i8* %hdl) ret i32 0 ; CHECK: call void @print(i32 4) -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 5) -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: call void @print(i32 6) ; CHECK: ret i32 0 } Index: llvm/test/Transforms/InstCombine/noalias-scope-decl.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/noalias-scope-decl.ll @@ -0,0 +1,83 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -instcombine -S < %s | FileCheck %s + +define void @test01(i8* %ptr) { +; CHECK-LABEL: @test01( +; CHECK-NEXT: store i8 42, i8* [[PTR:%.*]], align 1 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr + ret void +} + +define void @test02(i8* %ptr) { +; CHECK-LABEL: @test02( +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: store i8 42, i8* [[PTR:%.*]], align 1, !alias.scope !0 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr, !alias.scope !0 + ret void +} + +define void @test03(i8* %ptr) { +; CHECK-LABEL: @test03( +; CHECK-NEXT: store i8 42, i8* [[PTR:%.*]], align 1, !alias.scope !3 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr, !alias.scope !4 + ret void +} + +define void @test04(i8* %ptr) { +; CHECK-LABEL: @test04( +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: store i8 42, i8* [[PTR:%.*]], align 1, !alias.scope !4 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr, !alias.scope !5 + ret void +} + +define void @test11(i8* %ptr) { +; CHECK-LABEL: @test11( +; CHECK-NEXT: store i8 42, i8* [[PTR:%.*]], align 1, !noalias !0 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr, !noalias !0 + ret void +} + +define void @test12(i8* %ptr) { +; CHECK-LABEL: @test12( +; CHECK-NEXT: store i8 42, i8* [[PTR:%.*]], align 1, !noalias !3 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr, !noalias !4 + ret void +} + +define void @test13(i8* %ptr) { +; CHECK-LABEL: @test13( +; CHECK-NEXT: store i8 42, i8* [[PTR:%.*]], align 1, !noalias !4 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr, !noalias !5 + ret void +} + +declare void @llvm.experimental.noalias.scope.decl(metadata) + +!0 = !{ !1 } +!1 = distinct !{ !1, !2 } +!2 = distinct !{ !2 } +!3 = !{ !4 } +!4 = distinct !{ !4, !2 } +!5 = !{ !1, !4 } Index: llvm/test/Transforms/PhaseOrdering/inlining-alignment-assumptions.ll =================================================================== --- llvm/test/Transforms/PhaseOrdering/inlining-alignment-assumptions.ll +++ llvm/test/Transforms/PhaseOrdering/inlining-alignment-assumptions.ll @@ -95,7 +95,6 @@ define amdgpu_kernel void @caller2() { ; CHECK-LABEL: @caller2( -; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META0:metadata !.*]]) ; CHECK-NEXT: ret void ; %alloca = alloca i64, align 8, addrspace(5) Index: llvm/test/Transforms/PhaseOrdering/instcombine-sroa-inttoptr.ll =================================================================== --- llvm/test/Transforms/PhaseOrdering/instcombine-sroa-inttoptr.ll +++ llvm/test/Transforms/PhaseOrdering/instcombine-sroa-inttoptr.ll @@ -70,7 +70,6 @@ ; CHECK-NEXT: [[I2:%.*]] = alloca [[TMP0:%.*]], align 8 ; CHECK-NEXT: [[I1_SROA_0_0_I5_SROA_IDX:%.*]] = getelementptr inbounds [[TMP0]], %0* [[ARG:%.*]], i64 0, i32 0 ; CHECK-NEXT: [[I1_SROA_0_0_COPYLOAD:%.*]] = load i32*, i32** [[I1_SROA_0_0_I5_SROA_IDX]], align 8 -; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META0:metadata !.*]]) ; CHECK-NEXT: [[I_SROA_0_0_I6_SROA_IDX:%.*]] = getelementptr inbounds [[TMP0]], %0* [[I2]], i64 0, i32 0 ; CHECK-NEXT: store i32* [[I1_SROA_0_0_COPYLOAD]], i32** [[I_SROA_0_0_I6_SROA_IDX]], align 8 ; CHECK-NEXT: tail call void @_Z7escape01S(%0* nonnull byval(%0) align 8 [[I2]]) @@ -110,7 +109,6 @@ ; CHECK-NEXT: bb: ; CHECK-NEXT: [[I1_SROA_0_0_I4_SROA_IDX:%.*]] = getelementptr inbounds [[TMP0:%.*]], %0* [[ARG:%.*]], i64 0, i32 0 ; CHECK-NEXT: [[I1_SROA_0_0_COPYLOAD:%.*]] = load i32*, i32** [[I1_SROA_0_0_I4_SROA_IDX]], align 8 -; CHECK-NEXT: tail call void @llvm.experimental.noalias.scope.decl([[META3:metadata !.*]]) ; CHECK-NEXT: [[I5:%.*]] = tail call i32 @_Z4condv() ; CHECK-NEXT: [[I6_NOT:%.*]] = icmp eq i32 [[I5]], 0 ; CHECK-NEXT: br i1 [[I6_NOT]], label [[BB10:%.*]], label [[BB7:%.*]]