Index: llvm/include/llvm/Analysis/TargetTransformInfoImpl.h =================================================================== --- llvm/include/llvm/Analysis/TargetTransformInfoImpl.h +++ llvm/include/llvm/Analysis/TargetTransformInfoImpl.h @@ -557,6 +557,7 @@ 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: Index: llvm/include/llvm/Analysis/VectorUtils.h =================================================================== --- llvm/include/llvm/Analysis/VectorUtils.h +++ llvm/include/llvm/Analysis/VectorUtils.h @@ -304,7 +304,7 @@ /// 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); } Index: llvm/lib/Analysis/AliasSetTracker.cpp =================================================================== --- llvm/lib/Analysis/AliasSetTracker.cpp +++ llvm/lib/Analysis/AliasSetTracker.cpp @@ -438,6 +438,7 @@ break; // FIXME: Add lifetime/invariant intrinsics (See: PR30807). case Intrinsic::assume: + case Intrinsic::experimental_noalias_scope_decl: case Intrinsic::sideeffect: case Intrinsic::pseudoprobe: return; Index: llvm/lib/Analysis/MemorySSA.cpp =================================================================== --- llvm/lib/Analysis/MemorySSA.cpp +++ llvm/lib/Analysis/MemorySSA.cpp @@ -285,6 +285,7 @@ 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 @@ // 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 Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -536,6 +536,7 @@ 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: Index: llvm/lib/Analysis/VectorUtils.cpp =================================================================== --- llvm/lib/Analysis/VectorUtils.cpp +++ llvm/lib/Analysis/VectorUtils.cpp @@ -125,6 +125,7 @@ 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; Index: llvm/lib/CodeGen/Analysis.cpp =================================================================== --- llvm/lib/CodeGen/Analysis.cpp +++ llvm/lib/CodeGen/Analysis.cpp @@ -530,11 +530,12 @@ // 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)) Index: llvm/lib/Transforms/Scalar/EarlyCSE.cpp =================================================================== --- llvm/lib/Transforms/Scalar/EarlyCSE.cpp +++ llvm/lib/Transforms/Scalar/EarlyCSE.cpp @@ -1232,6 +1232,14 @@ 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'); Index: llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp =================================================================== --- llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp +++ llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp @@ -944,6 +944,13 @@ 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); Index: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp =================================================================== --- llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -2868,6 +2868,13 @@ 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 @@ 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 { Index: llvm/test/Analysis/AliasSet/intrinsics.ll =================================================================== --- llvm/test/Analysis/AliasSet/intrinsics.ll +++ llvm/test/Analysis/AliasSet/intrinsics.ll @@ -61,5 +61,25 @@ 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" } Index: llvm/test/Analysis/BasicAA/noalias-scope-decl.ll =================================================================== --- /dev/null +++ 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" } Index: llvm/test/Analysis/CostModel/X86/free-intrinsics.ll =================================================================== --- llvm/test/Analysis/CostModel/X86/free-intrinsics.ll +++ llvm/test/Analysis/CostModel/X86/free-intrinsics.ll @@ -6,6 +6,7 @@ ; 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 @@ ; 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 @@ ; %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 @@ 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 @@ !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" } Index: llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll =================================================================== --- llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll +++ llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll @@ -8,6 +8,7 @@ ; 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 @@ ; 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 @@ ; %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 @@ 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 @@ !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" } Index: llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll =================================================================== --- llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll +++ llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll @@ -6,6 +6,7 @@ ; 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 @@ ; 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 @@ ; %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 @@ 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 @@ !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" } Index: llvm/test/Analysis/MemorySSA/noalias-scope-decl.ll =================================================================== --- /dev/null +++ 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" } Index: llvm/test/Transforms/EarlyCSE/noalias_scope_decl.ll =================================================================== --- /dev/null +++ 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 } Index: llvm/test/Transforms/LoopVectorize/noalias-scope-decl.ll =================================================================== --- /dev/null +++ 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]]}