From 121cac01e8f8afe6ed2bb0b8ffe92f323776a716 Mon Sep 17 00:00:00 2001 From: Jeroen Dobbelaere Date: Tue, 19 Jan 2021 20:04:52 +0100 Subject: [PATCH] [noalias.decl] Look through llvm.experimental.noalias.scope.decl Just like llvm.assume, there are a lot of cases where we can just ignore llvm.experimental.noalias.scope.decl. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D93042 --- .../llvm/Analysis/TargetTransformInfoImpl.h | 1 + llvm/include/llvm/Analysis/VectorUtils.h | 2 +- llvm/lib/Analysis/AliasSetTracker.cpp | 1 + llvm/lib/Analysis/MemorySSA.cpp | 11 +- llvm/lib/Analysis/ValueTracking.cpp | 1 + llvm/lib/Analysis/VectorUtils.cpp | 1 + llvm/lib/CodeGen/Analysis.cpp | 7 +- llvm/lib/Transforms/Scalar/EarlyCSE.cpp | 8 ++ .../Vectorize/LoopVectorizationLegality.cpp | 7 ++ llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 10 +- llvm/test/Analysis/AliasSet/intrinsics.ll | 20 +++ llvm/test/Analysis/BasicAA/noalias-scope-decl.ll | 28 +++++ .../test/Analysis/CostModel/X86/free-intrinsics.ll | 7 ++ .../CostModel/free-intrinsics-datalayout.ll | 7 ++ .../Analysis/CostModel/free-intrinsics-no_info.ll | 7 ++ llvm/test/Analysis/MemorySSA/noalias-scope-decl.ll | 24 ++++ .../test/Transforms/EarlyCSE/noalias-scope-decl.ll | 38 ++++++ .../Transforms/LoopVectorize/noalias-scope-decl.ll | 140 +++++++++++++++++++++ 18 files changed, 313 insertions(+), 7 deletions(-) create mode 100644 llvm/test/Analysis/BasicAA/noalias-scope-decl.ll create mode 100644 llvm/test/Analysis/MemorySSA/noalias-scope-decl.ll create mode 100644 llvm/test/Transforms/EarlyCSE/noalias-scope-decl.ll create mode 100644 llvm/test/Transforms/LoopVectorize/noalias-scope-decl.ll diff --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h index 47de99b02d9..1e920143016 100644 --- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h +++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h @@ -557,6 +557,7 @@ public: case Intrinsic::is_constant: case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: + case Intrinsic::experimental_noalias_scope_decl: case Intrinsic::objectsize: case Intrinsic::ptr_annotation: case Intrinsic::var_annotation: diff --git a/llvm/include/llvm/Analysis/VectorUtils.h b/llvm/include/llvm/Analysis/VectorUtils.h index ce3cb22dcd6..26cb0e456ed 100644 --- a/llvm/include/llvm/Analysis/VectorUtils.h +++ b/llvm/include/llvm/Analysis/VectorUtils.h @@ -304,7 +304,7 @@ typedef unsigned ID; /// the incoming type is void, we return void. If the EC represents a /// scalar, we return the scalar type. inline Type *ToVectorTy(Type *Scalar, ElementCount EC) { - if (Scalar->isVoidTy() || EC.isScalar()) + if (Scalar->isVoidTy() || Scalar->isMetadataTy() || EC.isScalar()) return Scalar; return VectorType::get(Scalar, EC); } diff --git a/llvm/lib/Analysis/AliasSetTracker.cpp b/llvm/lib/Analysis/AliasSetTracker.cpp index 9b21fbf4c9b..486b4d99dfa 100644 --- a/llvm/lib/Analysis/AliasSetTracker.cpp +++ b/llvm/lib/Analysis/AliasSetTracker.cpp @@ -438,6 +438,7 @@ void AliasSetTracker::addUnknown(Instruction *Inst) { break; // FIXME: Add lifetime/invariant intrinsics (See: PR30807). case Intrinsic::assume: + case Intrinsic::experimental_noalias_scope_decl: case Intrinsic::sideeffect: case Intrinsic::pseudoprobe: return; diff --git a/llvm/lib/Analysis/MemorySSA.cpp b/llvm/lib/Analysis/MemorySSA.cpp index f0d27e0b2c6..52dca7d378e 100644 --- a/llvm/lib/Analysis/MemorySSA.cpp +++ b/llvm/lib/Analysis/MemorySSA.cpp @@ -285,6 +285,7 @@ instructionClobbersQuery(const MemoryDef *MD, const MemoryLocation &UseLoc, case Intrinsic::invariant_start: case Intrinsic::invariant_end: case Intrinsic::assume: + case Intrinsic::experimental_noalias_scope_decl: return {false, NoAlias}; case Intrinsic::dbg_addr: case Intrinsic::dbg_declare: @@ -1767,9 +1768,15 @@ MemoryUseOrDef *MemorySSA::createNewAccess(Instruction *I, // dependencies here. // FIXME: Replace this special casing with a more accurate modelling of // assume's control dependency. - if (IntrinsicInst *II = dyn_cast(I)) - if (II->getIntrinsicID() == Intrinsic::assume) + if (IntrinsicInst *II = dyn_cast(I)) { + switch (II->getIntrinsicID()) { + default: + break; + case Intrinsic::assume: + case Intrinsic::experimental_noalias_scope_decl: return nullptr; + } + } // Using a nonstandard AA pipelines might leave us with unexpected modref // results for I, so add a check to not model instructions that may not read diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 7f8f101d42a..4f0c7057089 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -536,6 +536,7 @@ bool llvm::isAssumeLikeIntrinsic(const Instruction *I) { case Intrinsic::invariant_end: case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: + case Intrinsic::experimental_noalias_scope_decl: case Intrinsic::objectsize: case Intrinsic::ptr_annotation: case Intrinsic::var_annotation: diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp index 1de17aac517..9a4c96b6f7c 100644 --- a/llvm/lib/Analysis/VectorUtils.cpp +++ b/llvm/lib/Analysis/VectorUtils.cpp @@ -125,6 +125,7 @@ Intrinsic::ID llvm::getVectorIntrinsicIDForCall(const CallInst *CI, if (isTriviallyVectorizable(ID) || ID == Intrinsic::lifetime_start || ID == Intrinsic::lifetime_end || ID == Intrinsic::assume || + ID == Intrinsic::experimental_noalias_scope_decl || ID == Intrinsic::sideeffect || ID == Intrinsic::pseudoprobe) return ID; return Intrinsic::not_intrinsic; diff --git a/llvm/lib/CodeGen/Analysis.cpp b/llvm/lib/CodeGen/Analysis.cpp index 48b69c8bc20..67eb079afb4 100644 --- a/llvm/lib/CodeGen/Analysis.cpp +++ b/llvm/lib/CodeGen/Analysis.cpp @@ -530,11 +530,12 @@ bool llvm::isInTailCallPosition(const CallBase &Call, const TargetMachine &TM) { // Pseudo probe intrinsics do not block tail call optimization either. if (isa(BBI)) continue; - // A lifetime end or assume intrinsic should not stop tail call - // optimization. + // A lifetime end, assume or noalias.decl intrinsic should not stop tail + // call optimization. if (const IntrinsicInst *II = dyn_cast(BBI)) if (II->getIntrinsicID() == Intrinsic::lifetime_end || - II->getIntrinsicID() == Intrinsic::assume) + II->getIntrinsicID() == Intrinsic::assume || + II->getIntrinsicID() == Intrinsic::experimental_noalias_scope_decl) continue; if (BBI->mayHaveSideEffects() || BBI->mayReadFromMemory() || !isSafeToSpeculativelyExecute(&*BBI)) diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp index f005f69519f..180a82917fa 100644 --- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp +++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp @@ -1232,6 +1232,14 @@ bool EarlyCSE::processNode(DomTreeNode *Node) { continue; } + // Likewise, noalias intrinsics don't actually write. + if (match(&Inst, + m_Intrinsic())) { + LLVM_DEBUG(dbgs() << "EarlyCSE skipping noalias intrinsic: " << Inst + << '\n'); + continue; + } + // Skip sideeffect intrinsics, for the same reason as assume intrinsics. if (match(&Inst, m_Intrinsic())) { LLVM_DEBUG(dbgs() << "EarlyCSE skipping sideeffect: " << Inst << '\n'); diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp index e3e522958c3..2b873954f88 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp @@ -944,6 +944,13 @@ bool LoopVectorizationLegality::blockCanBePredicated( continue; } + // Do not let llvm.experimental.noalias.scope.decl block the vectorization. + // TODO: there might be cases that it should block the vectorization. Let's + // ignore those for now. + if (match(&I, m_Intrinsic())) { + continue; + } + // We might be able to hoist the load. if (I.mayReadFromMemory()) { auto *LI = dyn_cast(&I); diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index 50e4ef01b61..865881bb429 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -2868,6 +2868,13 @@ void InnerLoopVectorizer::scalarizeInstruction(Instruction *Instr, VPUser &User, VPTransformState &State) { assert(!Instr->getType()->isAggregateType() && "Can't handle vectors"); + // llvm.experimental.noalias.scope.decl intrinsics must only be duplicated for + // the first lane and part. + if (auto *II = dyn_cast(Instr)) + if (Instance.Lane != 0 || Instance.Part != 0) + if (II->getIntrinsicID() == Intrinsic::experimental_noalias_scope_decl) + return; + setDebugLocFromInst(Builder, Instr); // Does this instruction return a value ? @@ -8225,7 +8232,8 @@ VPWidenCallRecipe *VPRecipeBuilder::tryToWidenCall(CallInst *CI, VFRange &Range, Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI); if (ID && (ID == Intrinsic::assume || ID == Intrinsic::lifetime_end || ID == Intrinsic::lifetime_start || ID == Intrinsic::sideeffect || - ID == Intrinsic::pseudoprobe)) + ID == Intrinsic::pseudoprobe || + ID == Intrinsic::experimental_noalias_scope_decl)) return nullptr; auto willWiden = [&](ElementCount VF) -> bool { diff --git a/llvm/test/Analysis/AliasSet/intrinsics.ll b/llvm/test/Analysis/AliasSet/intrinsics.ll index 12c1a91e7b8..6aeb56ba596 100644 --- a/llvm/test/Analysis/AliasSet/intrinsics.ll +++ b/llvm/test/Analysis/AliasSet/intrinsics.ll @@ -61,5 +61,25 @@ entry: ret void } +; CHECK: Alias sets for function 'test5': +; CHECK: Alias Set Tracker: 2 alias sets for 2 pointer values. +; CHECK: AliasSet[0x{{[0-9a-f]+}}, 1] must alias, Mod Pointers: (i8* %a, LocationSize::precise(1)) +; CHECK-NOT: 1 Unknown instruction +; CHECK: AliasSet[0x{{[0-9a-f]+}}, 1] must alias, Mod Pointers: (i8* %b, LocationSize::precise(1)) +define void @test5() { +entry: + %a = alloca i8, align 1 + %b = alloca i8, align 1 + store i8 1, i8* %a, align 1 + call void @llvm.experimental.noalias.scope.decl(metadata !0) + store i8 1, i8* %b, align 1 + ret void +} + declare void @llvm.assume(i1) declare void @llvm.experimental.guard(i1, ...) +declare void @llvm.experimental.noalias.scope.decl(metadata) + +!0 = !{ !1 } +!1 = distinct !{ !1, !2, !"test5: var" } +!2 = distinct !{ !2, !"test5" } diff --git a/llvm/test/Analysis/BasicAA/noalias-scope-decl.ll b/llvm/test/Analysis/BasicAA/noalias-scope-decl.ll new file mode 100644 index 00000000000..1f4b302d186 --- /dev/null +++ b/llvm/test/Analysis/BasicAA/noalias-scope-decl.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -basic-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32" + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) #0 +declare void @llvm.experimental.noalias.scope.decl(metadata) + +define void @test1(i8* %P, i8* %Q) nounwind ssp { + tail call void @llvm.experimental.noalias.scope.decl(metadata !0) + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) + ret void + +; CHECK-LABEL: Function: test1: + +; CHECK: MayAlias: i8* %P, i8* %Q +; CHECK: NoModRef: Ptr: i8* %P <-> tail call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK: NoModRef: Ptr: i8* %Q <-> tail call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) +; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) +; CHECK: NoModRef: tail call void @llvm.experimental.noalias.scope.decl(metadata !0) <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) +; CHECK: NoModRef: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i1 false) <-> tail call void @llvm.experimental.noalias.scope.decl(metadata !0) +} + + +attributes #0 = { nounwind } + +!0 = !{ !1 } +!1 = distinct !{ !1, !2, !"test1: var" } +!2 = distinct !{ !2, !"test1" } diff --git a/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll b/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll index 1a693c582f1..9870d9ae622 100644 --- a/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll +++ b/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll @@ -6,6 +6,7 @@ define i32 @trivially_free() { ; CHECK-SIZE-LABEL: 'trivially_free' ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !0) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.sideeffect() ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a1 = call {}* @llvm.invariant.start.p0i8(i64 1, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.invariant.end.p0i8({}* undef, i64 1, i8* undef) @@ -22,6 +23,7 @@ define i32 @trivially_free() { ; CHECK-THROUGHPUT-LABEL: 'trivially_free' ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !0) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.sideeffect() ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a1 = call {}* @llvm.invariant.start.p0i8(i64 1, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.invariant.end.p0i8({}* undef, i64 1, i8* undef) @@ -37,6 +39,7 @@ define i32 @trivially_free() { ; %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) call void @llvm.assume(i1 undef) + call void @llvm.experimental.noalias.scope.decl(metadata !4) call void @llvm.sideeffect() call void @llvm.dbg.declare(metadata i8** undef, metadata !0, metadata !DIExpression()) call void @llvm.dbg.value(metadata i64 undef, i64 undef, metadata !DIExpression(), metadata !DIExpression()) @@ -56,6 +59,7 @@ define i32 @trivially_free() { declare i32 @llvm.annotation.i32(i32, i8*, i8*, i32) declare void @llvm.assume(i1) +declare void @llvm.experimental.noalias.scope.decl(metadata) declare void @llvm.sideeffect() declare void @llvm.dbg.declare(metadata, metadata, metadata) declare void @llvm.dbg.value(metadata, i64, metadata, metadata) @@ -76,3 +80,6 @@ declare void @llvm.var.annotation(i8*, i8*, i8*, i32, i8*) !1 = distinct !DISubprogram(name: "dummy", line: 79, isLocal: true, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true) !2 = !DILabel(scope: !1, name: "label", file: !3, line: 7) !3 = !DIFile(filename: "debug-label.c", directory: "./") +!4 = !{ !4 } +!5 = distinct !{ !5, !6, !"foo: var" } +!6 = distinct !{ !6, !"foo" } diff --git a/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll b/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll index 787bb373cb8..b6b884c7c30 100644 --- a/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll +++ b/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll @@ -8,6 +8,7 @@ define i32 @trivially_free() { ; CHECK-SIZE-LABEL: 'trivially_free' ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !0) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.sideeffect() ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a1 = call {}* @llvm.invariant.start.p0i8(i64 1, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.invariant.end.p0i8({}* undef, i64 1, i8* undef) @@ -24,6 +25,7 @@ define i32 @trivially_free() { ; CHECK-THROUGHPUT-LABEL: 'trivially_free' ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !0) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.sideeffect() ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a1 = call {}* @llvm.invariant.start.p0i8(i64 1, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.invariant.end.p0i8({}* undef, i64 1, i8* undef) @@ -39,6 +41,7 @@ define i32 @trivially_free() { ; %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) call void @llvm.assume(i1 undef) + call void @llvm.experimental.noalias.scope.decl(metadata !4) call void @llvm.sideeffect() call void @llvm.dbg.declare(metadata i8** undef, metadata !0, metadata !DIExpression()) call void @llvm.dbg.value(metadata i64 undef, i64 undef, metadata !DIExpression(), metadata !DIExpression()) @@ -58,6 +61,7 @@ define i32 @trivially_free() { declare i32 @llvm.annotation.i32(i32, i8*, i8*, i32) declare void @llvm.assume(i1) +declare void @llvm.experimental.noalias.scope.decl(metadata) declare void @llvm.sideeffect() declare void @llvm.dbg.declare(metadata, metadata, metadata) declare void @llvm.dbg.value(metadata, i64, metadata, metadata) @@ -78,3 +82,6 @@ declare void @llvm.var.annotation(i8*, i8*, i8*, i32, i8*) !1 = distinct !DISubprogram(name: "dummy", line: 79, isLocal: true, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true) !2 = !DILabel(scope: !1, name: "label", file: !3, line: 7) !3 = !DIFile(filename: "debug-label.c", directory: "./") +!4 = !{ !4 } +!5 = distinct !{ !5, !6, !"foo: var" } +!6 = distinct !{ !6, !"foo" } diff --git a/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll b/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll index 6f31249ca77..fb5221b93b1 100644 --- a/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll +++ b/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll @@ -6,6 +6,7 @@ define i32 @trivially_free() { ; CHECK-SIZE-LABEL: 'trivially_free' ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !0) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.sideeffect() ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a1 = call {}* @llvm.invariant.start.p0i8(i64 1, i8* undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.invariant.end.p0i8({}* undef, i64 1, i8* undef) @@ -22,6 +23,7 @@ define i32 @trivially_free() { ; CHECK-THROUGHPUT-LABEL: 'trivially_free' ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !0) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.sideeffect() ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a1 = call {}* @llvm.invariant.start.p0i8(i64 1, i8* undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.invariant.end.p0i8({}* undef, i64 1, i8* undef) @@ -37,6 +39,7 @@ define i32 @trivially_free() { ; %a0 = call i32 @llvm.annotation.i32(i32 undef, i8* undef, i8* undef, i32 undef) call void @llvm.assume(i1 undef) + call void @llvm.experimental.noalias.scope.decl(metadata !4) call void @llvm.sideeffect() call void @llvm.dbg.declare(metadata i8** undef, metadata !0, metadata !DIExpression()) call void @llvm.dbg.value(metadata i64 undef, i64 undef, metadata !DIExpression(), metadata !DIExpression()) @@ -56,6 +59,7 @@ define i32 @trivially_free() { declare i32 @llvm.annotation.i32(i32, i8*, i8*, i32) declare void @llvm.assume(i1) +declare void @llvm.experimental.noalias.scope.decl(metadata) declare void @llvm.sideeffect() declare void @llvm.dbg.declare(metadata, metadata, metadata) declare void @llvm.dbg.value(metadata, i64, metadata, metadata) @@ -76,3 +80,6 @@ declare void @llvm.var.annotation(i8*, i8*, i8*, i32, i8*) !1 = distinct !DISubprogram(name: "dummy", line: 79, isLocal: true, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true) !2 = !DILabel(scope: !1, name: "label", file: !3, line: 7) !3 = !DIFile(filename: "debug-label.c", directory: "./") +!4 = !{ !4 } +!5 = distinct !{ !5, !6, !"foo: var" } +!6 = distinct !{ !6, !"foo" } diff --git a/llvm/test/Analysis/MemorySSA/noalias-scope-decl.ll b/llvm/test/Analysis/MemorySSA/noalias-scope-decl.ll new file mode 100644 index 00000000000..85bc32d6727 --- /dev/null +++ b/llvm/test/Analysis/MemorySSA/noalias-scope-decl.ll @@ -0,0 +1,24 @@ +; RUN: opt -basic-aa -memoryssa -enable-new-pm=0 -analyze < %s 2>&1 | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='print,verify' -disable-output < %s 2>&1 | FileCheck %s +; +; Ensures that llvm.experimental.noalias.scope.decl is treated as not reading or writing memory. + +declare void @llvm.experimental.noalias.scope.decl(metadata) + +define i32 @foo(i32* %a, i32* %b, i1 %c) { +; CHECK: 1 = MemoryDef(liveOnEntry) +; CHECK-NEXT: store i32 4 + store i32 4, i32* %a, align 4 +; CHECK-NOT: MemoryDef +; CHECK: call void @llvm.experimental.noalias.scope.decl + call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK: MemoryUse(1) +; CHECK-NEXT: %1 = load i32 + %1 = load i32, i32* %a, align 4 + ret i32 %1 +} + + +!0 = !{ !1 } +!1 = distinct !{ !1, !2, !"foo: var" } +!2 = distinct !{ !2, !"foo" } diff --git a/llvm/test/Transforms/EarlyCSE/noalias-scope-decl.ll b/llvm/test/Transforms/EarlyCSE/noalias-scope-decl.ll new file mode 100644 index 00000000000..6b441c27aad --- /dev/null +++ b/llvm/test/Transforms/EarlyCSE/noalias-scope-decl.ll @@ -0,0 +1,38 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S < %s -early-cse -earlycse-debug-hash | FileCheck %s + +; Store-to-load forwarding across a @llvm.experimental.noalias.scope.decl. + +define float @s2l(float* %p) { +; CHECK-LABEL: @s2l( +; CHECK-NEXT: store float 0.000000e+00, float* [[P:%.*]], align 4 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: ret float 0.000000e+00 +; + store float 0.0, float* %p + call void @llvm.experimental.noalias.scope.decl(metadata !0) + %t = load float, float* %p + ret float %t +} + +; Redundant load elimination across a @llvm.experimental.noalias.scope.decl. + +define float @rle(float* %p) { +; CHECK-LABEL: @rle( +; CHECK-NEXT: [[R:%.*]] = load float, float* [[P:%.*]], align 4 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: [[T:%.*]] = fadd float [[R]], [[R]] +; CHECK-NEXT: ret float [[T]] +; + %r = load float, float* %p + call void @llvm.experimental.noalias.scope.decl(metadata !0) + %s = load float, float* %p + %t = fadd float %r, %s + ret float %t +} + +declare void @llvm.experimental.noalias.scope.decl(metadata) + +!0 = !{ !1 } +!1 = distinct !{ !1, !2 } +!2 = distinct !{ !2 } diff --git a/llvm/test/Transforms/LoopVectorize/noalias-scope-decl.ll b/llvm/test/Transforms/LoopVectorize/noalias-scope-decl.ll new file mode 100644 index 00000000000..140fc219c1d --- /dev/null +++ b/llvm/test/Transforms/LoopVectorize/noalias-scope-decl.ll @@ -0,0 +1,140 @@ +; RUN: opt < %s -loop-vectorize -force-vector-width=4 -force-vector-interleave=2 -S | FileCheck %s + +define void @test1(float* noalias nocapture %a, float* noalias nocapture readonly %b) { +entry: + br label %for.body + +; CHECK-LABEL: @test1 +; CHECK: vector.body: +; CHECK: @llvm.experimental.noalias.scope.decl +; CHECK-NOT: @llvm.experimental.noalias.scope.decl +; CHECK: for.body: +; CHECK: @llvm.experimental.noalias.scope.decl +; CHECK-NOT: @llvm.experimental.noalias.scope.decl +; CHECK: ret void + +for.body: ; preds = %for.body, %entry + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %arrayidx = getelementptr inbounds float, float* %b, i64 %indvars.iv + %0 = load float, float* %arrayidx, align 4 + %cmp1 = fcmp ogt float %0, 1.000000e+02 + tail call void @llvm.experimental.noalias.scope.decl(metadata !0) + %add = fadd float %0, 1.000000e+00 + %arrayidx5 = getelementptr inbounds float, float* %a, i64 %indvars.iv + store float %add, float* %arrayidx5, align 4 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp eq i64 %indvars.iv, 1599 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} + +declare void @llvm.experimental.noalias.scope.decl(metadata) + +%struct.data = type { float*, float* } + +define void @test2(%struct.data* nocapture readonly %d) { +entry: + %b = getelementptr inbounds %struct.data, %struct.data* %d, i64 0, i32 1 + %0 = load float*, float** %b, align 8 + %ptrint = ptrtoint float* %0 to i64 + %maskedptr = and i64 %ptrint, 31 + %maskcond = icmp eq i64 %maskedptr, 0 + %a = getelementptr inbounds %struct.data, %struct.data* %d, i64 0, i32 0 + %1 = load float*, float** %a, align 8 + %ptrint2 = ptrtoint float* %1 to i64 + %maskedptr3 = and i64 %ptrint2, 31 + %maskcond4 = icmp eq i64 %maskedptr3, 0 + br label %for.body + +; CHECK-LABEL: @test2 +; CHECK: vector.body: +; CHECK: @llvm.experimental.noalias.scope.decl(metadata [[SCOPE0_LIST:!.*]]) +; CHECK: @llvm.experimental.noalias.scope.decl(metadata [[SCOPE4_LIST:!.*]]) +; CHECK-NOT: @llvm.experimental.noalias.scope.decl +; CHECK: for.body: +; CHECK: @llvm.experimental.noalias.scope.decl(metadata [[SCOPE0_LIST]]) +; CHECK: @llvm.experimental.noalias.scope.decl(metadata [[SCOPE4_LIST]]) +; CHECK-NOT: @llvm.experimental.noalias.scope.decl +; CHECK: ret void + +for.body: ; preds = %for.body, %entry + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + tail call void @llvm.experimental.noalias.scope.decl(metadata !0) + %arrayidx = getelementptr inbounds float, float* %0, i64 %indvars.iv + %2 = load float, float* %arrayidx, align 4 + %add = fadd float %2, 1.000000e+00 + tail call void @llvm.experimental.noalias.scope.decl(metadata !4) + %arrayidx5 = getelementptr inbounds float, float* %1, i64 %indvars.iv + store float %add, float* %arrayidx5, align 4 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp eq i64 %indvars.iv, 1599 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} + +define void @predicated_noalias_scope_decl(float* noalias nocapture readonly %a, float* noalias nocapture %b, i32 %n) { + +; Check that the vector.body still contains a llvm.experimental.noalias.scope.decl + +; CHECK-LABEL: @predicated_noalias_scope_decl( +; CHECK: vector.body: +; CHECK: call void @llvm.experimental.noalias.scope.decl +; CHECK-NOT: @llvm.experimental.noalias.scope.decl +; CHECK: scalar.ph: +; CHECK-NOT: @llvm.experimental.noalias.scope.decl +; CHECK: if.else: +; CHECK: call void @llvm.experimental.noalias.scope.decl +; CHECK-NOT: @llvm.experimental.noalias.scope.decl +; CHECK: } + +entry: + %cmp15 = icmp eq i32 %n, 0 + br i1 %cmp15, label %for.cond.cleanup, label %for.body.preheader + +for.body.preheader: ; preds = %entry + %0 = zext i32 %n to i64 + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %if.end5 + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + ret void + +for.body: ; preds = %for.body.preheader, %if.end5 + %indvars.iv = phi i64 [ 0, %for.body.preheader ], [ %indvars.iv.next, %if.end5 ] + %cmp1 = icmp ult i64 %indvars.iv, 495616 + br i1 %cmp1, label %if.end5, label %if.else + +if.else: ; preds = %for.body + %cmp2 = icmp ult i64 %indvars.iv, 991232 + tail call void @llvm.experimental.noalias.scope.decl(metadata !0) + br label %if.end5 + +if.end5: ; preds = %for.body, %if.else + %x.0 = phi float [ 4.200000e+01, %if.else ], [ 2.300000e+01, %for.body ] + %arrayidx = getelementptr inbounds float, float* %a, i64 %indvars.iv + %1 = load float, float* %arrayidx, align 4 + %mul = fmul float %x.0, %1 + %arrayidx7 = getelementptr inbounds float, float* %b, i64 %indvars.iv + store float %mul, float* %arrayidx7, align 4 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %cmp = icmp eq i64 %indvars.iv.next, %0 + br i1 %cmp, label %for.cond.cleanup.loopexit, label %for.body +} + +!0 = !{ !1 } +!1 = distinct !{ !1, !2 } +!2 = distinct !{ !2 } +!3 = distinct !{ !3, !2 } +!4 = !{ !3 } + +; CHECK: [[SCOPE0_LIST]] = !{[[SCOPE0:!.*]]} +; CHECK: [[SCOPE0]] = distinct !{[[SCOPE0]], [[SCOPE0_DOM:!.*]]} +; CHECK: [[SCOPE0_DOM]] = distinct !{[[SCOPE0_DOM]]} +; CHECK: [[SCOPE4_LIST]] = !{[[SCOPE4:!.*]]} +; CHECK: [[SCOPE4]] = distinct !{[[SCOPE4]], [[SCOPE0_DOM]]} -- 2.11.0