[llvm] r213949 - Convert noalias parameter attributes into noalias metadata during inlining

Hal Finkel hfinkel at anl.gov
Fri Jul 25 08:50:09 PDT 2014


Author: hfinkel
Date: Fri Jul 25 10:50:08 2014
New Revision: 213949

URL: http://llvm.org/viewvc/llvm-project?rev=213949&view=rev
Log:
Convert noalias parameter attributes into noalias metadata during inlining

This functionality is currently turned off by default.

Part of the motivation for introducing scoped-noalias metadata is to enable the
preservation of noalias parameter attribute information after inlining.
Sometimes this can be inferred from the code in the caller after inlining, but
often we simply lose valuable information.

The overall process if fairly simple:
 1. Create a new unqiue scope domain.
 2. For each (used) noalias parameter, create a new alias scope.
 3. For each pointer, collect the underlying objects. Add a noalias scope for
    each noalias parameter from which we're not derived (and has not been
    captured prior to that point).
 4. Add an alias.scope for each noalias parameter from which we might be
    derived (or has been captured before that point).

Note that the capture checks apply only if one of the underlying objects is not
an identified function-local object.

Added:
    llvm/trunk/test/Transforms/Inline/noalias.ll
    llvm/trunk/test/Transforms/Inline/noalias2.ll
Removed:
    llvm/trunk/test/Analysis/ScopedNoAliasAA/basic-hierarchy.ll
Modified:
    llvm/trunk/lib/Transforms/Utils/InlineFunction.cpp

Modified: llvm/trunk/lib/Transforms/Utils/InlineFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/InlineFunction.cpp?rev=213949&r1=213948&r2=213949&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/InlineFunction.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/InlineFunction.cpp Fri Jul 25 10:50:08 2014
@@ -17,7 +17,9 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/Analysis/CallGraph.h"
+#include "llvm/Analysis/CaptureTracking.h"
 #include "llvm/Analysis/InstructionSimplify.h"
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/IR/Attributes.h"
@@ -27,6 +29,7 @@
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Dominators.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
@@ -34,8 +37,15 @@
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Transforms/Utils/Local.h"
+#include "llvm/Support/CommandLine.h"
+#include <algorithm>
 using namespace llvm;
 
+static cl::opt<bool>
+EnableNoAliasConversion("enable-noalias-to-md-conversion", cl::init(false),
+  cl::Hidden,
+  cl::desc("Convert noalias attributes to metadata during inlining."));
+
 bool llvm::InlineFunction(CallInst *CI, InlineFunctionInfo &IFI,
                           bool InsertLifetime) {
   return InlineFunction(CallSite(CI), IFI, InsertLifetime);
@@ -358,6 +368,167 @@ static void CloneAliasScopeMetadata(Call
     MDNode::deleteTemporary(DummyNodes[i]);
 }
 
+/// AddAliasScopeMetadata - If the inlined function has noalias arguments, then
+/// add new alias scopes for each noalias argument, tag the mapped noalias
+/// parameters with noalias metadata specifying the new scope, and tag all
+/// non-derived loads, stores and memory intrinsics with the new alias scopes.
+static void AddAliasScopeMetadata(CallSite CS, ValueToValueMapTy &VMap,
+                                  const DataLayout *DL) {
+  if (!EnableNoAliasConversion)
+    return;
+
+  const Function *CalledFunc = CS.getCalledFunction();
+  SmallVector<const Argument *, 4> NoAliasArgs;
+
+  for (Function::const_arg_iterator I = CalledFunc->arg_begin(),
+       E = CalledFunc->arg_end(); I != E; ++I) {
+    if (I->hasNoAliasAttr() && !I->hasNUses(0))
+      NoAliasArgs.push_back(I);
+  }
+
+  if (NoAliasArgs.empty())
+    return;
+
+  // To do a good job, if a noalias variable is captured, we need to know if
+  // the capture point dominates the particular use we're considering.
+  DominatorTree DT;
+  DT.recalculate(const_cast<Function&>(*CalledFunc));
+
+  // noalias indicates that pointer values based on the argument do not alias
+  // pointer values which are not based on it. So we add a new "scope" for each
+  // noalias function argument. Accesses using pointers based on that argument
+  // become part of that alias scope, accesses using pointers not based on that
+  // argument are tagged as noalias with that scope.
+
+  DenseMap<const Argument *, MDNode *> NewScopes;
+  MDBuilder MDB(CalledFunc->getContext());
+
+  // Create a new scope domain for this function.
+  MDNode *NewDomain =
+    MDB.createAnonymousAliasScopeDomain(CalledFunc->getName());
+  for (unsigned i = 0, e = NoAliasArgs.size(); i != e; ++i) {
+    const Argument *A = NoAliasArgs[i];
+
+    std::string Name = CalledFunc->getName();
+    if (A->hasName()) {
+      Name += ": %";
+      Name += A->getName();
+    } else {
+      Name += ": argument ";
+      Name += utostr(i);
+    }
+
+    // Note: We always create a new anonymous root here. This is true regardless
+    // of the linkage of the callee because the aliasing "scope" is not just a
+    // property of the callee, but also all control dependencies in the caller.
+    MDNode *NewScope = MDB.createAnonymousAliasScope(NewDomain, Name);
+    NewScopes.insert(std::make_pair(A, NewScope));
+  }
+
+  // Iterate over all new instructions in the map; for all memory-access
+  // instructions, add the alias scope metadata.
+  for (ValueToValueMapTy::iterator VMI = VMap.begin(), VMIE = VMap.end();
+       VMI != VMIE; ++VMI) {
+    if (const Instruction *I = dyn_cast<Instruction>(VMI->first)) {
+      if (!VMI->second)
+        continue;
+
+      Instruction *NI = dyn_cast<Instruction>(VMI->second);
+      if (!NI)
+        continue;
+
+      SmallVector<const Value *, 2> PtrArgs;
+
+      if (const LoadInst *LI = dyn_cast<LoadInst>(I))
+        PtrArgs.push_back(LI->getPointerOperand());
+      else if (const StoreInst *SI = dyn_cast<StoreInst>(I))
+        PtrArgs.push_back(SI->getPointerOperand());
+      else if (const VAArgInst *VAAI = dyn_cast<VAArgInst>(I))
+        PtrArgs.push_back(VAAI->getPointerOperand());
+      else if (const AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(I))
+        PtrArgs.push_back(CXI->getPointerOperand());
+      else if (const AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(I))
+        PtrArgs.push_back(RMWI->getPointerOperand());
+      else if (const MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) {
+        PtrArgs.push_back(MI->getRawDest());
+        if (const MemTransferInst *MTI = dyn_cast<MemTransferInst>(MI))
+          PtrArgs.push_back(MTI->getRawSource());
+      }
+
+      // If we found no pointers, then this instruction is not suitable for
+      // pairing with an instruction to receive aliasing metadata.
+      // Simplification during cloning could make this happen, and skip these
+      // cases for now.
+      if (PtrArgs.empty())
+        continue;
+
+      // It is possible that there is only one underlying object, but you
+      // need to go through several PHIs to see it, and thus could be
+      // repeated in the Objects list.
+      SmallPtrSet<const Value *, 4> ObjSet;
+      SmallVector<Value *, 4> Scopes, NoAliases;
+
+      SmallSetVector<const Argument *, 4> NAPtrArgs;
+      for (unsigned i = 0, ie = PtrArgs.size(); i != ie; ++i) {
+        SmallVector<Value *, 4> Objects;
+        GetUnderlyingObjects(const_cast<Value*>(PtrArgs[i]),
+                             Objects, DL, /* MaxLookup = */ 0);
+
+        for (Value *O : Objects)
+          ObjSet.insert(O);
+      }
+
+      // Figure out if we're derived from anyhing that is not a noalias
+      // argument.
+      bool CanDeriveViaCapture = false;
+      for (const Value *V : ObjSet)
+        if (!isIdentifiedFunctionLocal(const_cast<Value*>(V))) {
+          CanDeriveViaCapture = true;
+          break;
+        }
+  
+      // First, we want to figure out all of the sets with which we definitely
+      // don't alias. Iterate over all noalias set, and add those for which:
+      //   1. The noalias argument is not in the set of objects from which we
+      //      definitely derive.
+      //   2. The noalias argument has not yet been captured.
+      for (const Argument *A : NoAliasArgs) {
+        if (!ObjSet.count(A) && (!CanDeriveViaCapture ||
+                                 A->hasNoCaptureAttr() ||
+                                 !PointerMayBeCapturedBefore(A,
+                                   /* ReturnCaptures */ false,
+                                   /* StoreCaptures */ false, I, &DT)))
+          NoAliases.push_back(NewScopes[A]);
+      }
+
+      if (!NoAliases.empty())
+        NI->setMetadata(LLVMContext::MD_noalias, MDNode::concatenate(
+          NI->getMetadata(LLVMContext::MD_noalias),
+            MDNode::get(CalledFunc->getContext(), NoAliases)));
+      // Next, we want to figure out all of the sets to which we might belong.
+      // We might below to a set if:
+      //  1. The noalias argument is in the set of underlying objects
+      // or
+      //  2. There is some non-noalias argument in our list and the no-alias
+      //     argument has been captured.
+      
+      for (const Argument *A : NoAliasArgs) {
+        if (ObjSet.count(A) || (CanDeriveViaCapture &&
+                                PointerMayBeCapturedBefore(A,
+                                  /* ReturnCaptures */ false,
+                                  /* StoreCaptures */ false,
+                                  I, &DT)))
+          Scopes.push_back(NewScopes[A]);
+      }
+
+      if (!Scopes.empty())
+        NI->setMetadata(LLVMContext::MD_alias_scope, MDNode::concatenate(
+          NI->getMetadata(LLVMContext::MD_alias_scope),
+            MDNode::get(CalledFunc->getContext(), Scopes)));
+    }
+  }
+}
+
 /// UpdateCallGraphAfterInlining - Once we have cloned code over from a callee
 /// into the caller, update the specified callgraph to reflect the changes we
 /// made.  Note that it's possible that not all code was copied over, so only
@@ -749,6 +920,9 @@ bool llvm::InlineFunction(CallSite CS, I
 
     // Clone existing noalias metadata if necessary.
     CloneAliasScopeMetadata(CS, VMap);
+
+    // Add noalias metadata if necessary.
+    AddAliasScopeMetadata(CS, VMap, IFI.DL);
   }
 
   // If there are any alloca instructions in the block that used to be the entry

Removed: llvm/trunk/test/Analysis/ScopedNoAliasAA/basic-hierarchy.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ScopedNoAliasAA/basic-hierarchy.ll?rev=213948&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/ScopedNoAliasAA/basic-hierarchy.ll (original)
+++ llvm/trunk/test/Analysis/ScopedNoAliasAA/basic-hierarchy.ll (removed)
@@ -1,80 +0,0 @@
-; RUN: opt < %s -basicaa -scoped-noalias -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
-target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
-define void @foo1(float* nocapture %a, float* nocapture readonly %c) #0 {
-entry:
-; CHECK-LABEL: Function: foo1
-  %0 = load float* %c, align 4, !alias.scope !0
-  %arrayidx.i = getelementptr inbounds float* %a, i64 5
-  store float %0, float* %arrayidx.i, align 4, !noalias !0
-
-  %1 = load float* %c, align 4
-  %arrayidx = getelementptr inbounds float* %a, i64 7
-  store float %1, float* %arrayidx, align 4
-
-  %2 = load float* %c, align 4, !alias.scope !1
-  %arrayidx.i2 = getelementptr inbounds float* %a, i64 15
-  store float %2, float* %arrayidx.i2, align 4, !noalias !3
-
-  %3 = load float* %c, align 4, !alias.scope !3
-  %arrayidx.i3 = getelementptr inbounds float* %a, i64 16
-  store float %3, float* %arrayidx.i3, align 4, !noalias !0
-
-  %4 = load float* %c, align 4, !alias.scope !5
-  %arrayidx.i4 = getelementptr inbounds float* %a, i64 17
-  store float %4, float* %arrayidx.i4, align 4, !noalias !3
-  ret void
-}
-
-attributes #0 = { nounwind uwtable }
-
-; A root scope (which doubles as a list of itself):
-!0 = metadata !{metadata !0}
-
-; Two child scopes (which must be self-referential to avoid being "uniqued"):
-!1 = metadata !{metadata !2}
-!2 = metadata !{metadata !2, metadata !0}
-
-!3 = metadata !{metadata !4}
-!4 = metadata !{metadata !4, metadata !0}
-
-; A list of the two children:
-!5 = metadata !{metadata !2, metadata !4}
-
-; CHECK: NoAlias:   %0 = load float* %c, align 4, !alias.scope !0 <->   store float %0, float* %arrayidx.i, align 4, !noalias !0
-; CHECK: MayAlias:   %0 = load float* %c, align 4, !alias.scope !0 <->   store float %1, float* %arrayidx, align 4
-; CHECK: MayAlias:   %0 = load float* %c, align 4, !alias.scope !0 <->   store float %2, float* %arrayidx.i2, align 4, !noalias !3
-; CHECK: NoAlias:   %0 = load float* %c, align 4, !alias.scope !0 <->   store float %3, float* %arrayidx.i3, align 4, !noalias !0
-; CHECK: MayAlias:   %0 = load float* %c, align 4, !alias.scope !0 <->   store float %4, float* %arrayidx.i4, align 4, !noalias !3
-; CHECK: MayAlias:   %1 = load float* %c, align 4 <->   store float %0, float* %arrayidx.i, align 4, !noalias !0
-; CHECK: MayAlias:   %1 = load float* %c, align 4 <->   store float %1, float* %arrayidx, align 4
-; CHECK: MayAlias:   %1 = load float* %c, align 4 <->   store float %2, float* %arrayidx.i2, align 4, !noalias !3
-; CHECK: MayAlias:   %1 = load float* %c, align 4 <->   store float %3, float* %arrayidx.i3, align 4, !noalias !0
-; CHECK: MayAlias:   %1 = load float* %c, align 4 <->   store float %4, float* %arrayidx.i4, align 4, !noalias !3
-; CHECK: NoAlias:   %2 = load float* %c, align 4, !alias.scope !1 <->   store float %0, float* %arrayidx.i, align 4, !noalias !0
-; CHECK: MayAlias:   %2 = load float* %c, align 4, !alias.scope !1 <->   store float %1, float* %arrayidx, align 4
-; CHECK: MayAlias:   %2 = load float* %c, align 4, !alias.scope !1 <->   store float %2, float* %arrayidx.i2, align 4, !noalias !3
-; CHECK: NoAlias:   %2 = load float* %c, align 4, !alias.scope !1 <->   store float %3, float* %arrayidx.i3, align 4, !noalias !0
-; CHECK: MayAlias:   %2 = load float* %c, align 4, !alias.scope !1 <->   store float %4, float* %arrayidx.i4, align 4, !noalias !3
-; CHECK: NoAlias:   %3 = load float* %c, align 4, !alias.scope !3 <->   store float %0, float* %arrayidx.i, align 4, !noalias !0
-; CHECK: MayAlias:   %3 = load float* %c, align 4, !alias.scope !3 <->   store float %1, float* %arrayidx, align 4
-; CHECK: NoAlias:   %3 = load float* %c, align 4, !alias.scope !3 <->   store float %2, float* %arrayidx.i2, align 4, !noalias !3
-; CHECK: NoAlias:   %3 = load float* %c, align 4, !alias.scope !3 <->   store float %3, float* %arrayidx.i3, align 4, !noalias !0
-; CHECK: NoAlias:   %3 = load float* %c, align 4, !alias.scope !3 <->   store float %4, float* %arrayidx.i4, align 4, !noalias !3
-; CHECK: NoAlias:   %4 = load float* %c, align 4, !alias.scope !5 <->   store float %0, float* %arrayidx.i, align 4, !noalias !0
-; CHECK: MayAlias:   %4 = load float* %c, align 4, !alias.scope !5 <->   store float %1, float* %arrayidx, align 4
-; CHECK: NoAlias:   %4 = load float* %c, align 4, !alias.scope !5 <->   store float %2, float* %arrayidx.i2, align 4, !noalias !3
-; CHECK: NoAlias:   %4 = load float* %c, align 4, !alias.scope !5 <->   store float %3, float* %arrayidx.i3, align 4, !noalias !0
-; CHECK: NoAlias:   %4 = load float* %c, align 4, !alias.scope !5 <->   store float %4, float* %arrayidx.i4, align 4, !noalias !3
-; CHECK: NoAlias:   store float %1, float* %arrayidx, align 4 <->   store float %0, float* %arrayidx.i, align 4, !noalias !0
-; CHECK: NoAlias:   store float %2, float* %arrayidx.i2, align 4, !noalias !3 <->   store float %0, float* %arrayidx.i, align 4, !noalias !0
-; CHECK: NoAlias:   store float %2, float* %arrayidx.i2, align 4, !noalias !3 <->   store float %1, float* %arrayidx, align 4
-; CHECK: NoAlias:   store float %3, float* %arrayidx.i3, align 4, !noalias !0 <->   store float %0, float* %arrayidx.i, align 4, !noalias !0
-; CHECK: NoAlias:   store float %3, float* %arrayidx.i3, align 4, !noalias !0 <->   store float %1, float* %arrayidx, align 4
-; CHECK: NoAlias:   store float %3, float* %arrayidx.i3, align 4, !noalias !0 <->   store float %2, float* %arrayidx.i2, align 4, !noalias !3
-; CHECK: NoAlias:   store float %4, float* %arrayidx.i4, align 4, !noalias !3 <->   store float %0, float* %arrayidx.i, align 4, !noalias !0
-; CHECK: NoAlias:   store float %4, float* %arrayidx.i4, align 4, !noalias !3 <->   store float %1, float* %arrayidx, align 4
-; CHECK: NoAlias:   store float %4, float* %arrayidx.i4, align 4, !noalias !3 <->   store float %2, float* %arrayidx.i2, align 4, !noalias !3
-; CHECK: NoAlias:   store float %4, float* %arrayidx.i4, align 4, !noalias !3 <->   store float %3, float* %arrayidx.i3, align 4, !noalias !0
-

Added: llvm/trunk/test/Transforms/Inline/noalias.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/noalias.ll?rev=213949&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/Inline/noalias.ll (added)
+++ llvm/trunk/test/Transforms/Inline/noalias.ll Fri Jul 25 10:50:08 2014
@@ -0,0 +1,76 @@
+; RUN: opt -inline -enable-noalias-to-md-conversion -S < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @hello(float* noalias nocapture %a, float* nocapture readonly %c) #0 {
+entry:
+  %0 = load float* %c, align 4
+  %arrayidx = getelementptr inbounds float* %a, i64 5
+  store float %0, float* %arrayidx, align 4
+  ret void
+}
+
+define void @foo(float* nocapture %a, float* nocapture readonly %c) #0 {
+entry:
+  tail call void @hello(float* %a, float* %c)
+  %0 = load float* %c, align 4
+  %arrayidx = getelementptr inbounds float* %a, i64 7
+  store float %0, float* %arrayidx, align 4
+  ret void
+}
+
+; CHECK: define void @foo(float* nocapture %a, float* nocapture readonly %c) #0 {
+; CHECK: entry:
+; CHECK:   %0 = load float* %c, align 4, !noalias !0
+; CHECK:   %arrayidx.i = getelementptr inbounds float* %a, i64 5
+; CHECK:   store float %0, float* %arrayidx.i, align 4, !alias.scope !0
+; CHECK:   %1 = load float* %c, align 4
+; CHECK:   %arrayidx = getelementptr inbounds float* %a, i64 7
+; CHECK:   store float %1, float* %arrayidx, align 4
+; CHECK:   ret void
+; CHECK: }
+
+define void @hello2(float* noalias nocapture %a, float* noalias nocapture %b, float* nocapture readonly %c) #0 {
+entry:
+  %0 = load float* %c, align 4
+  %arrayidx = getelementptr inbounds float* %a, i64 5
+  store float %0, float* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds float* %b, i64 8
+  store float %0, float* %arrayidx1, align 4
+  ret void
+}
+
+define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 {
+entry:
+  tail call void @hello2(float* %a, float* %b, float* %c)
+  %0 = load float* %c, align 4
+  %arrayidx = getelementptr inbounds float* %a, i64 7
+  store float %0, float* %arrayidx, align 4
+  ret void
+}
+
+; CHECK: define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 {
+; CHECK: entry:
+; CHECK:   %0 = load float* %c, align 4, !noalias !3
+; CHECK:   %arrayidx.i = getelementptr inbounds float* %a, i64 5
+; CHECK:   store float %0, float* %arrayidx.i, align 4, !alias.scope !7, !noalias !8
+; CHECK:   %arrayidx1.i = getelementptr inbounds float* %b, i64 8
+; CHECK:   store float %0, float* %arrayidx1.i, align 4, !alias.scope !8, !noalias !7
+; CHECK:   %1 = load float* %c, align 4
+; CHECK:   %arrayidx = getelementptr inbounds float* %a, i64 7
+; CHECK:   store float %1, float* %arrayidx, align 4
+; CHECK:   ret void
+; CHECK: }
+
+attributes #0 = { nounwind uwtable }
+
+; CHECK: !0 = metadata !{metadata !1}
+; CHECK: !1 = metadata !{metadata !1, metadata !2, metadata !"hello: %a"}
+; CHECK: !2 = metadata !{metadata !2, metadata !"hello"}
+; CHECK: !3 = metadata !{metadata !4, metadata !6}
+; CHECK: !4 = metadata !{metadata !4, metadata !5, metadata !"hello2: %a"}
+; CHECK: !5 = metadata !{metadata !5, metadata !"hello2"}
+; CHECK: !6 = metadata !{metadata !6, metadata !5, metadata !"hello2: %b"}
+; CHECK: !7 = metadata !{metadata !4}
+; CHECK: !8 = metadata !{metadata !6}
+

Added: llvm/trunk/test/Transforms/Inline/noalias2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/noalias2.ll?rev=213949&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/Inline/noalias2.ll (added)
+++ llvm/trunk/test/Transforms/Inline/noalias2.ll Fri Jul 25 10:50:08 2014
@@ -0,0 +1,97 @@
+; RUN: opt -inline -enable-noalias-to-md-conversion -S < %s | FileCheck %s
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @hello(float* noalias nocapture %a, float* noalias nocapture readonly %c) #0 {
+entry:
+  %0 = load float* %c, align 4
+  %arrayidx = getelementptr inbounds float* %a, i64 5
+  store float %0, float* %arrayidx, align 4
+  ret void
+}
+
+define void @foo(float* noalias nocapture %a, float* noalias nocapture readonly %c) #0 {
+entry:
+  tail call void @hello(float* %a, float* %c)
+  %0 = load float* %c, align 4
+  %arrayidx = getelementptr inbounds float* %a, i64 7
+  store float %0, float* %arrayidx, align 4
+  ret void
+}
+
+; CHECK: define void @foo(float* noalias nocapture %a, float* noalias nocapture readonly %c) #0 {
+; CHECK: entry:
+; CHECK:   %0 = load float* %c, align 4, !alias.scope !0, !noalias !3
+; CHECK:   %arrayidx.i = getelementptr inbounds float* %a, i64 5
+; CHECK:   store float %0, float* %arrayidx.i, align 4, !alias.scope !3, !noalias !0
+; CHECK:   %1 = load float* %c, align 4
+; CHECK:   %arrayidx = getelementptr inbounds float* %a, i64 7
+; CHECK:   store float %1, float* %arrayidx, align 4
+; CHECK:   ret void
+; CHECK: }
+
+define void @hello2(float* noalias nocapture %a, float* noalias nocapture %b, float* nocapture readonly %c) #0 {
+entry:
+  %0 = load float* %c, align 4
+  %arrayidx = getelementptr inbounds float* %a, i64 6
+  store float %0, float* %arrayidx, align 4
+  %arrayidx1 = getelementptr inbounds float* %b, i64 8
+  store float %0, float* %arrayidx1, align 4
+  ret void
+}
+
+; Check that when hello() is inlined into foo(), and then foo() is inlined into
+; foo2(), the noalias scopes are properly concatenated.
+define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 {
+entry:
+  tail call void @foo(float* %a, float* %c)
+  tail call void @hello2(float* %a, float* %b, float* %c)
+  %0 = load float* %c, align 4
+  %arrayidx = getelementptr inbounds float* %a, i64 7
+  store float %0, float* %arrayidx, align 4
+  ret void
+}
+
+; CHECK: define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 {
+; CHECK: entry:
+; CHECK:   %0 = load float* %c, align 4, !alias.scope !5, !noalias !10
+; CHECK:   %arrayidx.i.i = getelementptr inbounds float* %a, i64 5
+; CHECK:   store float %0, float* %arrayidx.i.i, align 4, !alias.scope !10, !noalias !5
+; CHECK:   %1 = load float* %c, align 4, !alias.scope !13, !noalias !14
+; CHECK:   %arrayidx.i = getelementptr inbounds float* %a, i64 7
+; CHECK:   store float %1, float* %arrayidx.i, align 4, !alias.scope !14, !noalias !13
+; CHECK:   %2 = load float* %c, align 4, !noalias !15
+; CHECK:   %arrayidx.i1 = getelementptr inbounds float* %a, i64 6
+; CHECK:   store float %2, float* %arrayidx.i1, align 4, !alias.scope !19, !noalias !20
+; CHECK:   %arrayidx1.i = getelementptr inbounds float* %b, i64 8
+; CHECK:   store float %2, float* %arrayidx1.i, align 4, !alias.scope !20, !noalias !19
+; CHECK:   %3 = load float* %c, align 4
+; CHECK:   %arrayidx = getelementptr inbounds float* %a, i64 7
+; CHECK:   store float %3, float* %arrayidx, align 4
+; CHECK:   ret void
+; CHECK: }
+
+; CHECK: !0 = metadata !{metadata !1}
+; CHECK: !1 = metadata !{metadata !1, metadata !2, metadata !"hello: %c"}
+; CHECK: !2 = metadata !{metadata !2, metadata !"hello"}
+; CHECK: !3 = metadata !{metadata !4}
+; CHECK: !4 = metadata !{metadata !4, metadata !2, metadata !"hello: %a"}
+; CHECK: !5 = metadata !{metadata !6, metadata !8}
+; CHECK: !6 = metadata !{metadata !6, metadata !7, metadata !"hello: %c"}
+; CHECK: !7 = metadata !{metadata !7, metadata !"hello"}
+; CHECK: !8 = metadata !{metadata !8, metadata !9, metadata !"foo: %c"}
+; CHECK: !9 = metadata !{metadata !9, metadata !"foo"}
+; CHECK: !10 = metadata !{metadata !11, metadata !12}
+; CHECK: !11 = metadata !{metadata !11, metadata !7, metadata !"hello: %a"}
+; CHECK: !12 = metadata !{metadata !12, metadata !9, metadata !"foo: %a"}
+; CHECK: !13 = metadata !{metadata !8}
+; CHECK: !14 = metadata !{metadata !12}
+; CHECK: !15 = metadata !{metadata !16, metadata !18}
+; CHECK: !16 = metadata !{metadata !16, metadata !17, metadata !"hello2: %a"}
+; CHECK: !17 = metadata !{metadata !17, metadata !"hello2"}
+; CHECK: !18 = metadata !{metadata !18, metadata !17, metadata !"hello2: %b"}
+; CHECK: !19 = metadata !{metadata !16}
+; CHECK: !20 = metadata !{metadata !18}
+
+attributes #0 = { nounwind uwtable }
+





More information about the llvm-commits mailing list