Index: llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp =================================================================== --- llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp +++ llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp @@ -17,6 +17,9 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Metadata.h" #include "llvm/IR/Type.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" @@ -30,8 +33,61 @@ STATISTIC(NumSimplified, "Number of redundant instructions removed"); +// @llvm.experimental.noalias.scope.decl calls declaring a scope that is never +// used by !alias.scope metadata can be omitted. +class NoAliasScopeDeclCleaner { + SmallVector NoAliasScopeDecls; + SmallPtrSet UsedAliasScopes; + bool Handled = false; + +public: + void analyse(Instruction &I) { + if (Handled) + return; + + if (auto *II = dyn_cast(&I)) + if (II->getIntrinsicID() == Intrinsic::experimental_noalias_scope_decl) + NoAliasScopeDecls.push_back(II); + + rememberUsedAliasScopes(I); + } + + bool removeDead() { + if (Handled) + return false; + + bool Changed = false; + for (auto *NSD : NoAliasScopeDecls) { + auto *MV = cast( + NSD->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)) + if (!UsedAliasScopes.contains(MD)) { + assert(NSD->use_empty() && + "llvm.experimental.noalias.scope.decl still in use ?"); + NSD->eraseFromParent(); + Changed = true; + } + } + Handled = true; + return Changed; + } + +private: + void rememberUsedAliasScopes(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); + } +}; + static bool runImpl(Function &F, const SimplifyQuery &SQ, OptimizationRemarkEmitter *ORE) { + NoAliasScopeDeclCleaner NSDCleaner; SmallPtrSet S1, S2, *ToSimplify = &S1, *Next = &S2; bool Changed = false; @@ -54,7 +110,10 @@ if (isInstructionTriviallyDead(&I)) { DeadInstsInBB.push_back(&I); Changed = true; - } else if (!I.use_empty()) { + continue; + } + NSDCleaner.analyse(I); + if (!I.use_empty()) { if (Value *V = SimplifyInstruction(&I, SQ, ORE)) { // Mark all uses for resimplification next time round the loop. for (User *U : I.users()) @@ -71,6 +130,9 @@ RecursivelyDeleteTriviallyDeadInstructions(DeadInstsInBB, SQ.TLI); } + if (NSDCleaner.removeDead()) + Changed = true; + // Place the list of instructions to simplify on the next loop iteration // into ToSimplify. std::swap(ToSimplify, Next); 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/InstSimplify/noalias-scope-decl.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstSimplify/noalias-scope-decl.ll @@ -0,0 +1,83 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -instsimplify -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:%.*]]