Index: llvm/include/llvm/InitializePasses.h
===================================================================
--- llvm/include/llvm/InitializePasses.h
+++ llvm/include/llvm/InitializePasses.h
@@ -102,6 +102,7 @@
void initializeCallSiteSplittingLegacyPassPass(PassRegistry&);
void initializeCalledValuePropagationLegacyPassPass(PassRegistry &);
void initializeCodeGenPreparePass(PassRegistry&);
+void initializeConnectNoAliasDeclLegacyPassPass(PassRegistry &);
void initializeConstantHoistingLegacyPassPass(PassRegistry&);
void initializeConstantMergeLegacyPassPass(PassRegistry&);
void initializeConstantPropagationPass(PassRegistry&);
Index: llvm/include/llvm/Transforms/Scalar.h
===================================================================
--- llvm/include/llvm/Transforms/Scalar.h
+++ llvm/include/llvm/Transforms/Scalar.h
@@ -34,6 +34,12 @@
//
FunctionPass *createConstantPropagationPass();
+//===----------------------------------------------------------------------===//
+//
+// ConnectNoAliasDecl - Connects llvm.noalias.XX intrinsics to llvm.noalias.decl
+//
+FunctionPass *createConnectNoAliasDeclPass();
+
//===----------------------------------------------------------------------===//
//
// AlignmentFromAssumptions - Use assume intrinsics to set load/store
Index: llvm/include/llvm/Transforms/Scalar/ConnectNoAliasDecl.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/Transforms/Scalar/ConnectNoAliasDecl.h
@@ -0,0 +1,34 @@
+//===- ConnectNoAliasDecl.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This pass connects side.noalias intrinsics to the corresponding
+/// llvm.noalias.decl, based on the alloca of the pointer.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_SCALAR_CONNECTNOALIASDECL_H
+#define LLVM_TRANSFORMS_SCALAR_CONNECTNOALIASDECL_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+class DominatorTree;
+
+class ConnectNoAliasDeclPass : public PassInfoMixin<ConnectNoAliasDeclPass> {
+public:
+ ConnectNoAliasDeclPass();
+
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+
+ // Glue for old PM
+ bool runImpl(Function &F);
+};
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_SCALAR_CONNECTNOALIASDECL_H
Index: llvm/include/llvm/Transforms/Utils/Cloning.h
===================================================================
--- llvm/include/llvm/Transforms/Utils/Cloning.h
+++ llvm/include/llvm/Transforms/Utils/Cloning.h
@@ -272,6 +272,11 @@
Function *Callee, int64_t entryDelta,
const ValueMap<const Value *, WeakTrackingVH> *VMap = nullptr);
+/// Connects noalias, side.noalias, noalias.copy.guard intrinsics to the
+/// corresponding llvm.noalias.decl, based on the alloca of the underlying
+/// p.addr.
+/// \returns true when the function was modified.
+bool propagateAndConnectNoAliasDecl(Function *F);
} // end namespace llvm
#endif // LLVM_TRANSFORMS_UTILS_CLONING_H
Index: llvm/lib/Passes/PassBuilder.cpp
===================================================================
--- llvm/lib/Passes/PassBuilder.cpp
+++ llvm/lib/Passes/PassBuilder.cpp
@@ -110,6 +110,7 @@
#include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h"
#include "llvm/Transforms/Scalar/BDCE.h"
#include "llvm/Transforms/Scalar/CallSiteSplitting.h"
+#include "llvm/Transforms/Scalar/ConnectNoAliasDecl.h"
#include "llvm/Transforms/Scalar/ConstantHoisting.h"
#include "llvm/Transforms/Scalar/CorrelatedValuePropagation.h"
#include "llvm/Transforms/Scalar/DCE.h"
Index: llvm/lib/Passes/PassRegistry.def
===================================================================
--- llvm/lib/Passes/PassRegistry.def
+++ llvm/lib/Passes/PassRegistry.def
@@ -162,6 +162,7 @@
FUNCTION_PASS("bounds-checking", BoundsCheckingPass())
FUNCTION_PASS("break-crit-edges", BreakCriticalEdgesPass())
FUNCTION_PASS("callsite-splitting", CallSiteSplittingPass())
+FUNCTION_PASS("connect-noaliasdecl", ConnectNoAliasDeclPass())
FUNCTION_PASS("consthoist", ConstantHoistingPass())
FUNCTION_PASS("convert-noalias", PropagateAndConvertNoAliasPass())
FUNCTION_PASS("chr", ControlHeightReductionPass())
Index: llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
===================================================================
--- llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
+++ llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
@@ -260,6 +260,7 @@
addInitialAliasAnalysisPasses(FPM);
FPM.add(createCFGSimplificationPass());
+ FPM.add(createConnectNoAliasDeclPass());
FPM.add(createSROAPass());
FPM.add(createEarlyCSEPass());
@@ -297,6 +298,7 @@
IP.HintThreshold = 325;
MPM.add(createFunctionInliningPass(IP));
+ MPM.add(createConnectNoAliasDeclPass());
MPM.add(createSROAPass());
MPM.add(createEarlyCSEPass()); // Catch trivial redundancies
@@ -333,6 +335,7 @@
void PassManagerBuilder::addFunctionSimplificationPasses(
legacy::PassManagerBase &MPM) {
// Start of function pass.
+ MPM.add(createConnectNoAliasDeclPass());
// Break up aggregate allocas, using SSAUpdater.
MPM.add(createSROAPass());
MPM.add(createEarlyCSEPass(true /* Enable mem-ssa. */)); // Catch trivial redundancies
@@ -423,6 +426,8 @@
// opened up by them.
addInstructionCombiningPass(MPM);
addExtensionsToPM(EP_Peephole, MPM);
+
+ MPM.add(createConnectNoAliasDeclPass());
// Propagate and Convert as early as possible.
// But do it after SROA!
MPM.add(createPropagateAndConvertNoAliasPass());
Index: llvm/lib/Transforms/Scalar/CMakeLists.txt
===================================================================
--- llvm/lib/Transforms/Scalar/CMakeLists.txt
+++ llvm/lib/Transforms/Scalar/CMakeLists.txt
@@ -3,6 +3,7 @@
AlignmentFromAssumptions.cpp
BDCE.cpp
CallSiteSplitting.cpp
+ ConnectNoAliasDecl.cpp
ConstantHoisting.cpp
ConstantProp.cpp
CorrelatedValuePropagation.cpp
Index: llvm/lib/Transforms/Scalar/ConnectNoAliasDecl.cpp
===================================================================
--- /dev/null
+++ llvm/lib/Transforms/Scalar/ConnectNoAliasDecl.cpp
@@ -0,0 +1,112 @@
+//===- ConnectNoAliasDecl.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This pass connects side.noalias intrinsics to the corresponding
+/// llvm.noalias.decl, based on the alloca of the pointer.
+///
+//===----------------------------------------------------------------------===//
+//
+// When the original restrict declaration is not directly available,
+// llvm.noalias, llvm.side.noalias and llvm.noalias.copy.guard can be associated
+// with an 'unknown' (out of function) noalias scope. After certain
+// optimizations, like SROA, inlining, ... it is possible that a
+// llvm.noalias.decl is associated to an alloca, to which a llvm.noalias,
+// llvm.side.noalias orllvm.noalias.copy.guard intrinsics is also associated.
+// When the latter intrinsics are still refering to the 'unknown' scope, we can
+// now refine the information by associating the llvm.noalias.decl and its
+// information to the other noalias intrinsics that are depending on the same
+// alloca.
+//
+// This pass will connect those llvm.noalias.decl to those
+// llvm.noalias,llvm.side.noalias and llvm.noalias.copy.guard. It will also
+// propagate the embedded information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/ConnectNoAliasDecl.h"
+#include "llvm/Analysis/GlobalsModRef.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/Pass.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+using namespace llvm;
+
+namespace {
+class ConnectNoAliasDeclLegacyPass : public FunctionPass {
+public:
+ static char ID; // Pass identification, replacement for typeid
+ ConnectNoAliasDeclLegacyPass() : FunctionPass(ID) {
+ initializeConnectNoAliasDeclLegacyPassPass(
+ *PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override;
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ // FIXME: is all of this valid ?
+ AU.addPreserved<GlobalsAAWrapperPass>();
+ AU.addPreserved<CallGraphWrapperPass>(); // FIXME: not sure this is
+ // valid. It ensures the same pass
+ // order as if this pass was not
+ // there
+ AU.addPreserved<DominatorTreeWrapperPass>();
+ AU.addRequiredTransitive<DominatorTreeWrapperPass>();
+ AU.setPreservesCFG();
+ }
+
+private:
+ ConnectNoAliasDeclPass Impl;
+};
+} // namespace
+
+char ConnectNoAliasDeclLegacyPass::ID = 0;
+INITIALIZE_PASS_BEGIN(
+ ConnectNoAliasDeclLegacyPass, "connect-noaliasdecl",
+ "Connect llvm.noalias.decl", false,
+ false) // to llvm.noalias/llvm.side.noalias/llvm.noalias.copy.guard
+ // intrinsics
+INITIALIZE_PASS_END(
+ ConnectNoAliasDeclLegacyPass, "connect-noaliasdecl",
+ "Connect llvm.noalias.decl", false,
+ false) // to llvm.noalias/llvm.side.noalias/llvm.noalias.copy.guard
+ // intrinsics
+
+bool ConnectNoAliasDeclLegacyPass::runOnFunction(Function &F) {
+ if (skipFunction(F))
+ return false;
+
+ return Impl.runImpl(F);
+}
+
+namespace llvm {
+
+bool ConnectNoAliasDeclPass::runImpl(Function &F) {
+ return llvm::propagateAndConnectNoAliasDecl(&F);
+}
+
+ConnectNoAliasDeclPass::ConnectNoAliasDeclPass() {}
+
+PreservedAnalyses ConnectNoAliasDeclPass::run(Function &F,
+ FunctionAnalysisManager &AM) {
+ bool Changed = runImpl(F);
+
+ if (!Changed)
+ return PreservedAnalyses::all();
+ PreservedAnalyses PA;
+ PA.preserve<GlobalsAA>();
+ //?? PA.preserve<CallGraphWrapperPass>(); // FIXME: not sure this is valid,
+ // see above
+
+ return PA;
+}
+
+FunctionPass *createConnectNoAliasDeclPass() {
+ return new ConnectNoAliasDeclLegacyPass();
+}
+} // namespace llvm
Index: llvm/lib/Transforms/Scalar/Scalar.cpp
===================================================================
--- llvm/lib/Transforms/Scalar/Scalar.cpp
+++ llvm/lib/Transforms/Scalar/Scalar.cpp
@@ -37,6 +37,7 @@
initializeBDCELegacyPassPass(Registry);
initializeAlignmentFromAssumptionsPass(Registry);
initializeCallSiteSplittingLegacyPassPass(Registry);
+ initializeConnectNoAliasDeclLegacyPassPass(Registry);
initializeConstantHoistingLegacyPassPass(Registry);
initializeConstantPropagationPass(Registry);
initializeCorrelatedValuePropagationPass(Registry);
Index: llvm/test/Other/opt-O2-pipeline.ll
===================================================================
--- llvm/test/Other/opt-O2-pipeline.ll
+++ llvm/test/Other/opt-O2-pipeline.ll
@@ -13,6 +13,7 @@
; CHECK-NEXT: Instrument function entry/exit with calls to e.g. mcount() (pre inlining)
; CHECK-NEXT: Simplify the CFG
; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Connect llvm.noalias.decl
; CHECK-NEXT: SROA
; CHECK-NEXT: Early CSE
; CHECK-NEXT: Propagate and Convert Noalias intrinsics
@@ -59,6 +60,7 @@
; CHECK-NEXT: Deduce function attributes
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Connect llvm.noalias.decl
; CHECK-NEXT: SROA
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
; CHECK-NEXT: Function Alias Analysis Results
@@ -151,6 +153,7 @@
; CHECK-NEXT: Lazy Block Frequency Analysis
; CHECK-NEXT: Optimization Remark Emitter
; CHECK-NEXT: Combine redundant instructions
+; CHECK-NEXT: Connect llvm.noalias.decl
; CHECK-NEXT: Propagate and Convert Noalias intrinsics
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
; CHECK-NEXT: Function Alias Analysis Results
Index: llvm/test/Other/opt-O3-pipeline.ll
===================================================================
--- llvm/test/Other/opt-O3-pipeline.ll
+++ llvm/test/Other/opt-O3-pipeline.ll
@@ -13,6 +13,7 @@
; CHECK-NEXT: Instrument function entry/exit with calls to e.g. mcount() (pre inlining)
; CHECK-NEXT: Simplify the CFG
; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Connect llvm.noalias.decl
; CHECK-NEXT: SROA
; CHECK-NEXT: Early CSE
; CHECK-NEXT: Propagate and Convert Noalias intrinsics
@@ -63,6 +64,7 @@
; CHECK-NEXT: Promote 'by reference' arguments to scalars
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Connect llvm.noalias.decl
; CHECK-NEXT: SROA
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
; CHECK-NEXT: Function Alias Analysis Results
@@ -156,6 +158,7 @@
; CHECK-NEXT: Lazy Block Frequency Analysis
; CHECK-NEXT: Optimization Remark Emitter
; CHECK-NEXT: Combine redundant instructions
+; CHECK-NEXT: Connect llvm.noalias.decl
; CHECK-NEXT: Propagate and Convert Noalias intrinsics
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
; CHECK-NEXT: Function Alias Analysis Results
Index: llvm/test/Other/opt-Os-pipeline.ll
===================================================================
--- llvm/test/Other/opt-Os-pipeline.ll
+++ llvm/test/Other/opt-Os-pipeline.ll
@@ -13,6 +13,7 @@
; CHECK-NEXT: Instrument function entry/exit with calls to e.g. mcount() (pre inlining)
; CHECK-NEXT: Simplify the CFG
; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Connect llvm.noalias.decl
; CHECK-NEXT: SROA
; CHECK-NEXT: Early CSE
; CHECK-NEXT: Propagate and Convert Noalias intrinsics
@@ -59,6 +60,7 @@
; CHECK-NEXT: Deduce function attributes
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Connect llvm.noalias.decl
; CHECK-NEXT: SROA
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
; CHECK-NEXT: Function Alias Analysis Results
@@ -138,6 +140,7 @@
; CHECK-NEXT: Lazy Block Frequency Analysis
; CHECK-NEXT: Optimization Remark Emitter
; CHECK-NEXT: Combine redundant instructions
+; CHECK-NEXT: Connect llvm.noalias.decl
; CHECK-NEXT: Propagate and Convert Noalias intrinsics
; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
; CHECK-NEXT: Function Alias Analysis Results
Index: llvm/test/Transforms/ConnectNoAliasDecl/basictest.ll
===================================================================
--- /dev/null
+++ llvm/test/Transforms/ConnectNoAliasDecl/basictest.ll
@@ -0,0 +1,179 @@
+; RUN: opt < %s -connect-noaliasdecl -verify -S | FileCheck %s
+; RUN: opt < %s -passes=connect-noaliasdecl,verify -S | FileCheck %s
+
+target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
+
+
+%struct.FOO = type { i32*, i32*, i32* }
+
+; Function Attrs: nounwind
+define dso_local void @test_01_before(i32** %_p, i32 %c) #0 !noalias !2 {
+entry:
+ %rp = alloca [2 x i32*], align 4
+ %other = alloca i32*, align 4
+ %local_tmp = alloca i32*, align 4
+ %tmp.0 = bitcast [2 x i32*]* %rp to i8*
+ %.fca.0.gep = getelementptr inbounds [2 x i32*], [2 x i32*]* %rp, i32 0, i32 0
+ %.fca.1.gep = getelementptr inbounds [2 x i32*], [2 x i32*]* %rp, i32 0, i32 1
+ call void @llvm.lifetime.start.p0i8(i64 8, i8* %tmp.0) #5, !noalias !5
+ %tmp.1 = call i8* @llvm.noalias.decl.p0i8.p0a2p0i32.i32([2 x i32*]* %rp, i32 0, metadata !7)
+ %tmp.2 = load i32*, i32** %_p, align 4, !tbaa !8, !noalias !5
+ store i32* %tmp.2, i32** %.fca.0.gep, align 4, !tbaa !8, !noalias !5
+ %arrayinit.element = getelementptr inbounds i32*, i32** %.fca.0.gep, i32 1
+ %arrayidx1 = getelementptr inbounds i32*, i32** %_p, i32 1
+ %tmp.3 = load i32*, i32** %arrayidx1, align 4, !tbaa !8, !noalias !5
+ store i32* %tmp.3, i32** %arrayinit.element, align 4, !tbaa !8, !noalias !5
+ %tmp.4 = bitcast i32** %other to i8*
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %tmp.4) #5, !noalias !5
+ %arrayidx2 = getelementptr inbounds i32*, i32** %_p, i32 2
+ %tmp.5 = load i32*, i32** %arrayidx2, align 4, !tbaa !8, !noalias !5
+ store i32* %tmp.5, i32** %other, align 4, !tbaa !8, !noalias !5
+ %tobool = icmp ne i32 %c, 0
+ %cond = select i1 %tobool, i32** %.fca.0.gep, i32** %other
+ %tmp.6 = load i32*, i32** %arrayinit.element, align 4, !tbaa !8, !noalias !5
+ %through_local_tmp = call i32* @llvm.noalias.p0i32.p0i8.p0p0i32.i32(i32* %tmp.6, i8* null, i32** %arrayinit.element, i32 0, metadata !2), !tbaa !8, !noalias !5
+ %tmp.7 = call i32* @llvm.noalias.p0i32.p0i8.p0p0i32.i32(i32* %through_local_tmp, i8* null, i32** %local_tmp, i32 0, metadata !2), !tbaa !8, !noalias !5
+ %tmp.8 = load i32, i32* %tmp.7, align 4, !tbaa !12, !noalias !5
+ %tmp.9 = load i32*, i32** %.fca.0.gep, align 4, !tbaa !8, !noalias !5
+ %tmp.10 = call i32* @llvm.noalias.p0i32.p0i8.p0p0i32.i32(i32* %tmp.9, i8* null, i32** %.fca.0.gep, i32 0, metadata !2), !tbaa !8, !noalias !5
+ store i32 %tmp.8, i32* %tmp.10, align 4, !tbaa !12, !noalias !5
+ %tmp.11 = load i32*, i32** %cond, align 4, !tbaa !8, !noalias !5
+ %tmp.12 = call i32* @llvm.noalias.p0i32.p0i8.p0p0i32.i32(i32* %tmp.11, i8* null, i32** %cond, i32 0, metadata !2), !tbaa !8, !noalias !5
+ store i32 42, i32* %tmp.12, align 4, !tbaa !12, !noalias !5
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %tmp.4) #5
+ call void @llvm.lifetime.end.p0i8(i64 8, i8* %tmp.0) #5
+ ret void
+}
+
+; CHECK-LABEL: @test_01_before(
+; CHECK: %tmp.1 = call i8* @llvm.noalias.decl.p0i8.p0a2p0i32.i32([2 x i32*]* %rp, i32 0, metadata !7)
+; CHECK: %through_local_tmp = call i32* @llvm.noalias.p0i32.p0i8.p0p0i32.i32(i32* %tmp.6, i8* %tmp.1, i32** %arrayinit.element, i32 0, metadata !7), !tbaa !8, !noalias !5
+; CHECK: %tmp.10 = call i32* @llvm.noalias.p0i32.p0i8.p0p0i32.i32(i32* %tmp.9, i8* %tmp.1, i32** %.fca.0.gep, i32 0, metadata !7), !tbaa !8, !noalias !5
+; CHECK: %tmp.12 = call i32* @llvm.noalias.p0i32.p0i8.p0p0i32.i32(i32* %tmp.11, i8* null, i32** %cond, i32 0, metadata !2), !tbaa !8, !noalias !5
+; CHECK-NOT: llvm.noalias
+
+; Function Attrs: nounwind
+define dso_local void @test_02(i32** %_p, i32 %c) #0 !noalias !14 {
+entry:
+ %foo = alloca %struct.FOO, align 4
+ %tmp = alloca %struct.FOO, align 4
+ %tmp.1 = call i8* @llvm.noalias.decl.p0i8.p0s_struct.FOOs.i32(%struct.FOO* %foo, i32 0, metadata !17)
+ %tmp.10 = call i8* @llvm.noalias.decl.p0i8.p0s_struct.FOOs.i32(%struct.FOO* %tmp, i32 0, metadata !19)
+ %tmp.12 = call %struct.FOO* @llvm.noalias.copy.guard.p0s_struct.FOOs.p0i8(%struct.FOO* %foo, i8* null, metadata !21, metadata !14)
+ %tmp.13 = load %struct.FOO, %struct.FOO* %tmp.12, align 4, !noalias !25
+ store %struct.FOO %tmp.13, %struct.FOO* %tmp, !noalias !25
+ ret void
+}
+
+; CHECK-LABEL: @test_02(
+; CHECK: %tmp.1 = call i8* @llvm.noalias.decl.p0i8.p0s_struct.FOOs.i32(%struct.FOO* %foo, i32 0, metadata !17)
+; CHECK: %tmp.10 = call i8* @llvm.noalias.decl.p0i8.p0s_struct.FOOs.i32(%struct.FOO* %tmp, i32 0, metadata !19)
+; CHECK: %tmp.12 = call %struct.FOO* @llvm.noalias.copy.guard.p0s_struct.FOOs.p0i8(%struct.FOO* %foo, i8* %tmp.1, metadata !21, metadata !17)
+; CHECK-NOT: llvm.noalias
+
+; Function Attrs: nounwind
+define dso_local void @test_01_after(i32** %_p, i32 %c) #0 !noalias !2 {
+entry:
+ %rp = alloca [2 x i32*], align 4
+ %local_tmp = alloca i32*, align 4
+ %other = alloca i32*, align 4
+ %.fca.0.gep = getelementptr inbounds [2 x i32*], [2 x i32*]* %rp, i32 0, i32 0
+ %.fca.1.gep = getelementptr inbounds [2 x i32*], [2 x i32*]* %rp, i32 0, i32 1
+ %tmp.0 = bitcast [2 x i32*]* %rp to i8*
+ call void @llvm.lifetime.start.p0i8(i64 8, i8* %tmp.0) #5, !noalias !5
+ %tmp.1 = call i8* @llvm.noalias.decl.p0i8.p0a2p0i32.i32([2 x i32*]* %rp, i32 0, metadata !7)
+ %tmp.2 = load i32*, i32** %_p, noalias_sidechannel i32** undef, align 4, !tbaa !8, !noalias !5
+ store i32* %tmp.2, i32** %.fca.0.gep, noalias_sidechannel i32** undef, align 4, !tbaa !8, !noalias !5
+ %arrayinit.element = getelementptr inbounds i32*, i32** %.fca.0.gep, i32 1
+ %arrayidx1 = getelementptr inbounds i32*, i32** %_p, i32 1
+ %tmp.3 = load i32*, i32** %arrayidx1, noalias_sidechannel i32** undef, align 4, !tbaa !8, !noalias !5
+ store i32* %tmp.3, i32** %arrayinit.element, noalias_sidechannel i32** undef, align 4, !tbaa !8, !noalias !5
+ %tmp.4 = bitcast i32** %other to i8*
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %tmp.4) #5, !noalias !5
+ %arrayidx2 = getelementptr inbounds i32*, i32** %_p, i32 2
+ %tmp.5 = load i32*, i32** %arrayidx2, noalias_sidechannel i32** undef, align 4, !tbaa !8, !noalias !5
+ store i32* %tmp.5, i32** %other, noalias_sidechannel i32** undef, align 4, !tbaa !8, !noalias !5
+ %tobool = icmp ne i32 %c, 0
+ %cond = select i1 %tobool, i32** %.fca.0.gep, i32** %other
+ %tmp.6 = load i32*, i32** %arrayinit.element, noalias_sidechannel i32** undef, align 4, !tbaa !8, !noalias !5
+ %through_local_tmp = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %tmp.6, i8* null, i32** %arrayinit.element, i32** undef, i32 0, metadata !2), !tbaa !8, !noalias !5
+ %tmp.7 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %through_local_tmp, i8* null, i32** %local_tmp, i32** undef, i32 0, metadata !2), !tbaa !8, !noalias !5
+ %tmp.8 = load i32, i32* %tmp.6, noalias_sidechannel i32* %tmp.7, align 4, !tbaa !12, !noalias !5
+ %tmp.9 = load i32*, i32** %.fca.0.gep, noalias_sidechannel i32** undef, align 4, !tbaa !8, !noalias !5
+ %tmp.10 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %tmp.9, i8* null, i32** %.fca.0.gep, i32** undef, i32 0, metadata !2), !tbaa !8, !noalias !5
+ store i32 %tmp.8, i32* %tmp.9, noalias_sidechannel i32* %tmp.10, align 4, !tbaa !12, !noalias !5
+ %tmp.11 = load i32*, i32** %cond, noalias_sidechannel i32** undef, align 4, !tbaa !8, !noalias !5
+ %tmp.12 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %tmp.11, i8* null, i32** %cond, i32** undef, i32 0, metadata !2), !tbaa !8, !noalias !5
+ store i32 42, i32* %tmp.11, noalias_sidechannel i32* %tmp.12, align 4, !tbaa !12, !noalias !5
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %tmp.4) #5
+ call void @llvm.lifetime.end.p0i8(i64 8, i8* %tmp.0) #5
+ ret void
+}
+
+; CHECK-LABEL: @test_01_after(
+; CHECK: %tmp.1 = call i8* @llvm.noalias.decl.p0i8.p0a2p0i32.i32([2 x i32*]* %rp, i32 0, metadata !7)
+; CHECK: %through_local_tmp = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %tmp.6, i8* %tmp.1, i32** %arrayinit.element, i32** undef, i32 0, metadata !7), !tbaa !8, !noalias !5
+; CHECK: %tmp.10 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %tmp.9, i8* %tmp.1, i32** %.fca.0.gep, i32** undef, i32 0, metadata !7), !tbaa !8, !noalias !5
+; CHECK: %tmp.12 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %tmp.11, i8* null, i32** %cond, i32** undef, i32 0, metadata !2), !tbaa !8, !noalias !5
+; CHECK-NOT: llvm.noalias
+
+; CHECK: declare
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: argmemonly nounwind
+declare i8* @llvm.noalias.decl.p0i8.p0a2p0i32.i32([2 x i32*]*, i32, metadata) #1
+
+; Function Attrs: argmemonly nounwind speculatable
+declare i32* @llvm.noalias.p0i32.p0i8.p0p0i32.i32(i32*, i8*, i32**, i32, metadata) #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
+
+; Function Attrs: argmemonly nounwind
+declare i8* @llvm.noalias.decl.p0i8.p0s_struct.FOOs.i32(%struct.FOO*, i32, metadata) #1
+
+; Function Attrs: nounwind readnone
+declare %struct.FOO* @llvm.noalias.copy.guard.p0s_struct.FOOs.p0i8(%struct.FOO*, i8*, metadata, metadata) #3
+
+; Function Attrs: nounwind readnone speculatable
+declare i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #4
+
+
+attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { argmemonly nounwind }
+attributes #2 = { argmemonly nounwind speculatable }
+attributes #3 = { nounwind readnone }
+attributes #4 = { nounwind readnone speculatable }
+attributes #5 = { nounwind }
+
+!llvm.module.flags = !{!0}
+!llvm.ident = !{!1}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{!"clang version 10.0.0 (sgasip@krachtcs10:/u/sgasip/ipd/repositories/llvm_ipd 8efa7b085788c7ef2e29af74da59051ee86c2fd1)"}
+!2 = !{!3}
+!3 = distinct !{!3, !4, !"test_01: unknown scope"}
+!4 = distinct !{!4, !"test_01"}
+!5 = !{!6, !3}
+!6 = distinct !{!6, !4, !"test_01: rp"}
+!7 = !{!6}
+!8 = !{!9, !9, i64 0, i64 4}
+!9 = !{!10, i64 4, !"any pointer"}
+!10 = !{!11, i64 1, !"omnipotent char"}
+!11 = !{!"Simple C/C++ TBAA"}
+!12 = !{!13, !13, i64 0, i64 4}
+!13 = !{!10, i64 4, !"int"}
+!14 = !{!15}
+!15 = distinct !{!15, !16, !"test_02: unknown scope"}
+!16 = distinct !{!16, !"test_02"}
+!17 = !{!18}
+!18 = distinct !{!18, !16, !"test_02: foo"}
+!19 = !{!20}
+!20 = distinct !{!20, !16, !"test_02: tmp"}
+!21 = !{!22, !23, !24}
+!22 = !{i64 -1, i64 0}
+!23 = !{i64 -1, i64 1}
+!24 = !{i64 -1, i64 2}
+!25 = !{!20, !18, !15}