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<const MDNode *, 8> UsedAliasScopesAndLists;
+ SmallPtrSet<const MDNode *, 8> 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<MDNode>(ScopeList);
+ if (!MDScopeList || !Container.insert(MDScopeList).second)
+ return;
+ for (auto &MDOperand : MDScopeList->operands())
+ if (auto *MDScope = dyn_cast<MDNode>(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<NoAliasScopeDeclInst>(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<MDNode>(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.
///
SmallVector<Instruction*, 128> InstrsForInstCombineWorklist;
DenseMap<Constant *, Constant *> FoldedConstants;
+ AliasScopeTracker SeenAliasScopes;
do {
BasicBlock *BB = Worklist.pop_back_val();
// 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<DbgInfoIntrinsic>(Inst))
+ if (!isa<DbgInfoIntrinsic>(Inst)) {
InstrsForInstCombineWorklist.push_back(Inst);
+ SeenAliasScopes.analyse(Inst);
+ }
}
// Recursively visit successors. If this is a branch or switch on a
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);
--- /dev/null
+; 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 }