From dcc7706fcf2438b92d6f619e63c5db4880042ed2 Mon Sep 17 00:00:00 2001 From: Jeroen Dobbelaere Date: Sun, 24 Jan 2021 13:55:50 +0100 Subject: [PATCH] [InstCombine] Remove unused llvm.experimental.noalias.scope.decl A @llvm.experimental.noalias.scope.decl is only useful if there is !alias.scope and !noalias metadata that uses the declared scope. When that is not the case for at least one of the two, the intrinsic call can as well be removed. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D95141 --- .../InstCombine/InstructionCombining.cpp | 57 ++++++- .../Coroutines/coro-retcon-resume-values.ll | 3 - .../Transforms/Coroutines/coro-retcon-value.ll | 3 - llvm/test/Transforms/Coroutines/coro-retcon.ll | 1 - llvm/test/Transforms/Coroutines/ex2.ll | 2 - llvm/test/Transforms/Coroutines/ex3.ll | 2 - llvm/test/Transforms/Coroutines/ex4.ll | 2 - .../Transforms/InstCombine/noalias-scope-decl.ll | 170 +++++++++++++++++++++ .../inlining-alignment-assumptions.ll | 1 - .../PhaseOrdering/instcombine-sroa-inttoptr.ll | 2 - 10 files changed, 225 insertions(+), 18 deletions(-) create mode 100644 llvm/test/Transforms/InstCombine/noalias-scope-decl.ll diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 2f8a80a..518e909 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3766,6 +3766,55 @@ bool InstCombinerImpl::run() { return MadeIRChange; } +// Track the scopes used by !alias.scope and !noalias. In a function, a +// @llvm.experimental.noalias.scope.decl is only useful if that scope is used +// by both sets. If not, the declaration of the scope can be safely omitted. +// The MDNode of the scope can be omitted as well for the instructions that are +// part of this function. We do not do that at this point, as this might become +// too time consuming to do. +class AliasScopeTracker { + SmallPtrSet UsedAliasScopesAndLists; + SmallPtrSet UsedNoAliasScopesAndLists; + +public: + void analyse(Instruction *I) { + // This seems to be faster than checking 'mayReadOrWriteMemory()'. + if (!I->hasMetadataOtherThanDebugLoc()) + return; + + auto Track = [](Metadata *ScopeList, auto &Container) { + const auto *MDScopeList = dyn_cast_or_null(ScopeList); + if (!MDScopeList || !Container.insert(MDScopeList).second) + return; + for (auto &MDOperand : MDScopeList->operands()) + if (auto *MDScope = dyn_cast(MDOperand)) + Container.insert(MDScope); + }; + + Track(I->getMetadata(LLVMContext::MD_alias_scope), UsedAliasScopesAndLists); + Track(I->getMetadata(LLVMContext::MD_noalias), UsedNoAliasScopesAndLists); + } + + bool isNoAliasScopeDeclDead(Instruction *Inst) { + NoAliasScopeDeclInst *Decl = dyn_cast(Inst); + if (!Decl) + return false; + + assert(Decl->use_empty() && + "llvm.experimental.noalias.scope.decl in use ?"); + const MDNode *MDSL = Decl->getScopeList(); + assert(MDSL->getNumOperands() == 1 && + "llvm.experimental.noalias.scope should refer to a single scope"); + auto &MDOperand = MDSL->getOperand(0); + if (auto *MD = dyn_cast(MDOperand)) + return !UsedAliasScopesAndLists.contains(MD) || + !UsedNoAliasScopesAndLists.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. /// @@ -3784,6 +3833,7 @@ static bool prepareICWorklistFromFunction(Function &F, const DataLayout &DL, SmallVector InstrsForInstCombineWorklist; DenseMap FoldedConstants; + AliasScopeTracker SeenAliasScopes; do { BasicBlock *BB = Worklist.pop_back_val(); @@ -3830,8 +3880,10 @@ static bool prepareICWorklistFromFunction(Function &F, const DataLayout &DL, // Skip processing debug intrinsics in InstCombine. Processing these call instructions // consumes non-trivial amount of time and provides no value for the optimization. - if (!isa(Inst)) + if (!isa(Inst)) { InstrsForInstCombineWorklist.push_back(Inst); + SeenAliasScopes.analyse(Inst); + } } // Recursively visit successors. If this is a branch or switch on a @@ -3879,7 +3931,8 @@ static bool prepareICWorklistFromFunction(Function &F, const DataLayout &DL, 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); diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll index 993fc5d..c76ad50 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll @@ -67,10 +67,7 @@ entry: ; CHECK-NEXT: entry: ; 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 diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-value.ll b/llvm/test/Transforms/Coroutines/coro-retcon-value.ll index 42201a2..2c66b6a 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-value.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-value.ll @@ -79,17 +79,14 @@ entry: ; CHECK: [[SLOT:%.*]] = bitcast [8 x i8]* [[BUFFER]] to i32* ; CHECK-NEXT: store i32 4, i32* [[SLOT]], align 4 ; CHECK-NEXT: call void @print(i32 4) -; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl ; CHECK-NEXT: [[LOAD:%.*]] = load i32, i32* [[SLOT]], align 4 ; 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: [[LOAD:%.*]] = load i32, i32* [[SLOT]], align 4 ; 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*) diff --git a/llvm/test/Transforms/Coroutines/coro-retcon.ll b/llvm/test/Transforms/Coroutines/coro-retcon.ll index 2534af8..48e0b64 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon.ll @@ -78,7 +78,6 @@ entry: ; 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) { diff --git a/llvm/test/Transforms/Coroutines/ex2.ll b/llvm/test/Transforms/Coroutines/ex2.ll index 820f538..584bc90 100644 --- a/llvm/test/Transforms/Coroutines/ex2.ll +++ b/llvm/test/Transforms/Coroutines/ex2.ll @@ -49,9 +49,7 @@ return: 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 } diff --git a/llvm/test/Transforms/Coroutines/ex3.ll b/llvm/test/Transforms/Coroutines/ex3.ll index c75c7a1..85cf53f 100644 --- a/llvm/test/Transforms/Coroutines/ex3.ll +++ b/llvm/test/Transforms/Coroutines/ex3.ll @@ -53,9 +53,7 @@ return: 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 } diff --git a/llvm/test/Transforms/Coroutines/ex4.ll b/llvm/test/Transforms/Coroutines/ex4.ll index 1a26107..e60bc2c 100644 --- a/llvm/test/Transforms/Coroutines/ex4.ll +++ b/llvm/test/Transforms/Coroutines/ex4.ll @@ -50,9 +50,7 @@ entry: 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 } diff --git a/llvm/test/Transforms/InstCombine/noalias-scope-decl.ll b/llvm/test/Transforms/InstCombine/noalias-scope-decl.ll new file mode 100644 index 0000000..1251579 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/noalias-scope-decl.ll @@ -0,0 +1,170 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -instcombine -S < %s | FileCheck %s + +define void @test01(i8* %ptr0, i8* %ptr1) { +; CHECK-LABEL: @test01( +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1 +; CHECK-NEXT: store i8 43, i8* [[PTR1:%.*]], align 1 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0 + store i8 43, i8* %ptr1 + ret void +} + +define void @test02_keep(i8* %ptr0, i8* %ptr1) { +; CHECK-LABEL: @test02_keep( +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !alias.scope !0 +; CHECK-NEXT: store i8 43, i8* [[PTR1:%.*]], align 1, !noalias !3 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !alias.scope !0 + store i8 43, i8* %ptr1, !noalias !5 + ret void +} + +define void @test03(i8* %ptr0, i8* %ptr1) { +; CHECK-LABEL: @test03( +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !alias.scope !4 +; CHECK-NEXT: store i8 43, i8* [[PTR1:%.*]], align 1, !noalias !3 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !alias.scope !4 + store i8 43, i8* %ptr1, !noalias !5 + ret void +} + +define void @test04_keep(i8* %ptr0, i8* %ptr1) { +; CHECK-LABEL: @test04_keep( +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !alias.scope !3 +; CHECK-NEXT: store i8 43, i8* [[PTR1:%.*]], align 1, !noalias !3 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !alias.scope !5 + store i8 43, i8* %ptr1, !noalias !5 + ret void +} + +define void @test05_keep(i8* %ptr0, i8* %ptr1) { +; CHECK-LABEL: @test05_keep( +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !alias.scope !3 +; CHECK-NEXT: store i8 43, i8* [[PTR1:%.*]], align 1, !noalias !0 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !alias.scope !5 + store i8 43, i8* %ptr1, !noalias !0 + ret void +} + +define void @test06(i8* %ptr0, i8* %ptr1) { +; CHECK-LABEL: @test06( +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !alias.scope !3 +; CHECK-NEXT: store i8 43, i8* [[PTR1:%.*]], align 1, !noalias !4 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !alias.scope !5 + store i8 43, i8* %ptr1, !noalias !4 + ret void +} + +define void @test07(i8* %ptr0, i8* %ptr1) { +; CHECK-LABEL: @test07( +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !alias.scope !0 +; CHECK-NEXT: store i8 43, i8* [[PTR1:%.*]], align 1, !noalias !4 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !alias.scope !0 + store i8 43, i8* %ptr1, !noalias !4 + ret void +} + +define void @test08(i8* %ptr0, i8* %ptr1) { +; CHECK-LABEL: @test08( +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !alias.scope !4 +; CHECK-NEXT: store i8 43, i8* [[PTR1:%.*]], align 1, !noalias !0 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !alias.scope !4 + store i8 43, i8* %ptr1, !noalias !0 + ret void +} + +define void @test11(i8* %ptr0) { +; CHECK-LABEL: @test11( +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !alias.scope !0 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !alias.scope !0 + ret void +} + +define void @test12(i8* %ptr0) { +; CHECK-LABEL: @test12( +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !alias.scope !4 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !alias.scope !4 + ret void +} + +define void @test13(i8* %ptr0) { +; CHECK-LABEL: @test13( +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !alias.scope !3 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !alias.scope !5 + ret void +} + +define void @test14(i8* %ptr0) { +; CHECK-LABEL: @test14( +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !noalias !0 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !noalias !0 + ret void +} + +define void @test15(i8* %ptr0) { +; CHECK-LABEL: @test15( +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !noalias !4 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !noalias !4 + ret void +} + +define void @test16(i8* %ptr0) { +; CHECK-LABEL: @test16( +; CHECK-NEXT: store i8 42, i8* [[PTR0:%.*]], align 1, !noalias !3 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 42, i8* %ptr0, !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 } diff --git a/llvm/test/Transforms/PhaseOrdering/inlining-alignment-assumptions.ll b/llvm/test/Transforms/PhaseOrdering/inlining-alignment-assumptions.ll index 9e96ba0..4fe75883 100644 --- a/llvm/test/Transforms/PhaseOrdering/inlining-alignment-assumptions.ll +++ b/llvm/test/Transforms/PhaseOrdering/inlining-alignment-assumptions.ll @@ -95,7 +95,6 @@ define internal void @callee2(i64* noalias sret(i64) align 32 %arg) { 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) diff --git a/llvm/test/Transforms/PhaseOrdering/instcombine-sroa-inttoptr.ll b/llvm/test/Transforms/PhaseOrdering/instcombine-sroa-inttoptr.ll index 2ce1c49..9052fd5 100644 --- a/llvm/test/Transforms/PhaseOrdering/instcombine-sroa-inttoptr.ll +++ b/llvm/test/Transforms/PhaseOrdering/instcombine-sroa-inttoptr.ll @@ -70,7 +70,6 @@ define dso_local i32* @_Z3foo1S(%0* byval(%0) align 8 %arg) { ; 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 @@ define dso_local i32* @_Z3bar1S(%0* byval(%0) align 8 %arg) { ; 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:%.*]] -- 2.7.4