[llvm-branch-commits] [llvm-branch] r84104 - in /llvm/branches/Apple/Leela: lib/Analysis/BasicAliasAnalysis.cpp test/Analysis/BasicAA/2009-10-13-GEP-BaseNoAlias.ll test/Analysis/BasicAA/phi-aa.ll

Bob Wilson bob.wilson at apple.com
Wed Oct 14 08:55:03 PDT 2009


Author: bwilson
Date: Wed Oct 14 10:55:02 2009
New Revision: 84104

URL: http://llvm.org/viewvc/llvm-project?rev=84104&view=rev
Log:
$ svn merge -c 84000 https://bwilson@llvm.org/svn/llvm-project/llvm/trunk
--- Merging r84000 into '.':
U    lib/Analysis/BasicAliasAnalysis.cpp
$ svn merge -c 84038 https://bwilson@llvm.org/svn/llvm-project/llvm/trunk
--- Merging r84038 into '.':
A    test/Analysis/BasicAA/phi-aa.ll
G    lib/Analysis/BasicAliasAnalysis.cpp
$ svn merge -c 84069 https://bwilson@llvm.org/svn/llvm-project/llvm/trunk
--- Merging r84069 into '.':
U    test/Analysis/BasicAA/phi-aa.ll
$ svn merge -c 84072 https://bwilson@llvm.org/svn/llvm-project/llvm/trunk
--- Merging r84072 into '.':
G    lib/Analysis/BasicAliasAnalysis.cpp
$ svn merge -c 84074 https://bwilson@llvm.org/svn/llvm-project/llvm/trunk
--- Merging r84074 into '.':
G    lib/Analysis/BasicAliasAnalysis.cpp
$ svn merge -c 84079 https://bwilson@llvm.org/svn/llvm-project/llvm/trunk
--- Merging r84079 into '.':
A    test/Analysis/BasicAA/2009-10-13-GEP-BaseNoAlias.ll
G    lib/Analysis/BasicAliasAnalysis.cpp
$ svn merge -c 84080 https://bwilson@llvm.org/svn/llvm-project/llvm/trunk
--- Merging r84080 into '.':
G    lib/Analysis/BasicAliasAnalysis.cpp

Added:
    llvm/branches/Apple/Leela/test/Analysis/BasicAA/2009-10-13-GEP-BaseNoAlias.ll
      - copied unchanged from r84079, llvm/trunk/test/Analysis/BasicAA/2009-10-13-GEP-BaseNoAlias.ll
    llvm/branches/Apple/Leela/test/Analysis/BasicAA/phi-aa.ll
      - copied, changed from r84038, llvm/trunk/test/Analysis/BasicAA/phi-aa.ll
Modified:
    llvm/branches/Apple/Leela/lib/Analysis/BasicAliasAnalysis.cpp

Modified: llvm/branches/Apple/Leela/lib/Analysis/BasicAliasAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/branches/Apple/Leela/lib/Analysis/BasicAliasAnalysis.cpp?rev=84104&r1=84103&r2=84104&view=diff

==============================================================================
--- llvm/branches/Apple/Leela/lib/Analysis/BasicAliasAnalysis.cpp (original)
+++ llvm/branches/Apple/Leela/lib/Analysis/BasicAliasAnalysis.cpp Wed Oct 14 10:55:02 2009
@@ -27,6 +27,7 @@
 #include "llvm/Operator.h"
 #include "llvm/Pass.h"
 #include "llvm/Target/TargetData.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Compiler.h"
@@ -201,7 +202,12 @@
     static char ID; // Class identification, replacement for typeinfo
     BasicAliasAnalysis() : NoAA(&ID) {}
     AliasResult alias(const Value *V1, unsigned V1Size,
-                      const Value *V2, unsigned V2Size);
+                      const Value *V2, unsigned V2Size) {
+      assert(VisitedPHIs.empty() && "VisitedPHIs must be cleared after use!");
+      AliasResult Alias = aliasCheck(V1, V1Size, V2, V2Size);
+      VisitedPHIs.clear();
+      return Alias;
+    }
 
     ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size);
     ModRefResult getModRefInfo(CallSite CS1, CallSite CS2);
@@ -215,6 +221,22 @@
     bool pointsToConstantMemory(const Value *P);
 
   private:
+    // VisitedPHIs - Track PHI nodes visited by a aliasCheck() call.
+    SmallSet<const PHINode*, 16> VisitedPHIs;
+
+    // aliasGEP - Provide a bunch of ad-hoc rules to disambiguate a GEP instruction
+    // against another.
+    AliasResult aliasGEP(const Value *V1, unsigned V1Size,
+                         const Value *V2, unsigned V2Size);
+
+    // aliasPHI - Provide a bunch of ad-hoc rules to disambiguate a PHI instruction
+    // against another.
+    AliasResult aliasPHI(const PHINode *PN, unsigned PNSize,
+                         const Value *V2, unsigned V2Size);
+
+    AliasResult aliasCheck(const Value *V1, unsigned V1Size,
+                           const Value *V2, unsigned V2Size);
+
     // CheckGEPInstructions - Check two GEP instructions with known
     // must-aliasing base pointers.  This checks to see if the index expressions
     // preclude the pointers from aliasing...
@@ -308,61 +330,12 @@
   return NoAA::getModRefInfo(CS1, CS2);
 }
 
-
-// alias - Provide a bunch of ad-hoc rules to disambiguate in common cases, such
-// as array references.
+// aliasGEP - Provide a bunch of ad-hoc rules to disambiguate a GEP instruction
+// against another.
 //
 AliasAnalysis::AliasResult
-BasicAliasAnalysis::alias(const Value *V1, unsigned V1Size,
-                          const Value *V2, unsigned V2Size) {
-  // Strip off any casts if they exist.
-  V1 = V1->stripPointerCasts();
-  V2 = V2->stripPointerCasts();
-
-  // Are we checking for alias of the same value?
-  if (V1 == V2) return MustAlias;
-
-  if (!isa<PointerType>(V1->getType()) || !isa<PointerType>(V2->getType()))
-    return NoAlias;  // Scalars cannot alias each other
-
-  // Figure out what objects these things are pointing to if we can.
-  const Value *O1 = V1->getUnderlyingObject();
-  const Value *O2 = V2->getUnderlyingObject();
-
-  if (O1 != O2) {
-    // If V1/V2 point to two different objects we know that we have no alias.
-    if (isIdentifiedObject(O1) && isIdentifiedObject(O2))
-      return NoAlias;
-  
-    // Arguments can't alias with local allocations or noalias calls.
-    if ((isa<Argument>(O1) && (isa<AllocationInst>(O2) || isNoAliasCall(O2))) ||
-        (isa<Argument>(O2) && (isa<AllocationInst>(O1) || isNoAliasCall(O1))))
-      return NoAlias;
-
-    // Most objects can't alias null.
-    if ((isa<ConstantPointerNull>(V2) && isKnownNonNull(O1)) ||
-        (isa<ConstantPointerNull>(V1) && isKnownNonNull(O2)))
-      return NoAlias;
-  }
-  
-  // If the size of one access is larger than the entire object on the other
-  // side, then we know such behavior is undefined and can assume no alias.
-  LLVMContext &Context = V1->getContext();
-  if (TD)
-    if ((V1Size != ~0U && isObjectSmallerThan(O2, V1Size, Context, *TD)) ||
-        (V2Size != ~0U && isObjectSmallerThan(O1, V2Size, Context, *TD)))
-      return NoAlias;
-  
-  // If one pointer is the result of a call/invoke and the other is a
-  // non-escaping local object, then we know the object couldn't escape to a
-  // point where the call could return it.
-  if ((isa<CallInst>(O1) || isa<InvokeInst>(O1)) &&
-      isNonEscapingLocalObject(O2) && O1 != O2)
-    return NoAlias;
-  if ((isa<CallInst>(O2) || isa<InvokeInst>(O2)) &&
-      isNonEscapingLocalObject(O1) && O1 != O2)
-    return NoAlias;
-  
+BasicAliasAnalysis::aliasGEP(const Value *V1, unsigned V1Size,
+                             const Value *V2, unsigned V2Size) {
   // If we have two gep instructions with must-alias'ing base pointers, figure
   // out if the indexes to the GEP tell us anything about the derived pointer.
   // Note that we also handle chains of getelementptr instructions as well as
@@ -382,8 +355,8 @@
         GEP1->getOperand(0)->getType() == GEP2->getOperand(0)->getType() &&
         // All operands are the same, ignoring the base.
         std::equal(GEP1->op_begin()+1, GEP1->op_end(), GEP2->op_begin()+1))
-      return alias(GEP1->getOperand(0), V1Size, GEP2->getOperand(0), V2Size);
-    
+      return aliasCheck(GEP1->getOperand(0), V1Size,
+                        GEP2->getOperand(0), V2Size);
     
     // Drill down into the first non-gep value, to test for must-aliasing of
     // the base pointers.
@@ -400,7 +373,7 @@
     const Value *BasePtr2 = GEP2->getOperand(0);
 
     // Do the base pointers alias?
-    AliasResult BaseAlias = alias(BasePtr1, ~0U, BasePtr2, ~0U);
+    AliasResult BaseAlias = aliasCheck(BasePtr1, ~0U, BasePtr2, ~0U);
     if (BaseAlias == NoAlias) return NoAlias;
     if (BaseAlias == MustAlias) {
       // If the base pointers alias each other exactly, check to see if we can
@@ -430,63 +403,174 @@
   // instruction.  If one pointer is a GEP with a non-zero index of the other
   // pointer, we know they cannot alias.
   //
-  if (isGEP(V2)) {
-    std::swap(V1, V2);
-    std::swap(V1Size, V2Size);
-  }
+  if (V1Size == ~0U || V2Size == ~0U)
+    return MayAlias;
 
-  if (V1Size != ~0U && V2Size != ~0U)
-    if (isGEP(V1)) {
-      SmallVector<Value*, 16> GEPOperands;
-      const Value *BasePtr = GetGEPOperands(V1, GEPOperands);
-
-      AliasResult R = alias(BasePtr, V1Size, V2, V2Size);
-      if (R == MustAlias) {
-        // If there is at least one non-zero constant index, we know they cannot
-        // alias.
-        bool ConstantFound = false;
-        bool AllZerosFound = true;
-        for (unsigned i = 0, e = GEPOperands.size(); i != e; ++i)
-          if (const Constant *C = dyn_cast<Constant>(GEPOperands[i])) {
-            if (!C->isNullValue()) {
-              ConstantFound = true;
-              AllZerosFound = false;
-              break;
-            }
-          } else {
-            AllZerosFound = false;
-          }
+  SmallVector<Value*, 16> GEPOperands;
+  const Value *BasePtr = GetGEPOperands(V1, GEPOperands);
+
+  AliasResult R = aliasCheck(BasePtr, ~0U, V2, V2Size);
+  if (R != MustAlias)
+    // If V2 may alias GEP base pointer, conservatively returns MayAlias.
+    // If V2 is known not to alias GEP base pointer, then the two values
+    // cannot alias per GEP semantics: "A pointer value formed from a
+    // getelementptr instruction is associated with the addresses associated
+    // with the first operand of the getelementptr".
+    return R;
+
+  // If there is at least one non-zero constant index, we know they cannot
+  // alias.
+  bool ConstantFound = false;
+  bool AllZerosFound = true;
+  for (unsigned i = 0, e = GEPOperands.size(); i != e; ++i)
+    if (const Constant *C = dyn_cast<Constant>(GEPOperands[i])) {
+      if (!C->isNullValue()) {
+        ConstantFound = true;
+        AllZerosFound = false;
+        break;
+      }
+    } else {
+      AllZerosFound = false;
+    }
 
-        // If we have getelementptr <ptr>, 0, 0, 0, 0, ... and V2 must aliases
-        // the ptr, the end result is a must alias also.
-        if (AllZerosFound)
-          return MustAlias;
+  // If we have getelementptr <ptr>, 0, 0, 0, 0, ... and V2 must aliases
+  // the ptr, the end result is a must alias also.
+  if (AllZerosFound)
+    return MustAlias;
 
-        if (ConstantFound) {
-          if (V2Size <= 1 && V1Size <= 1)  // Just pointer check?
-            return NoAlias;
+  if (ConstantFound) {
+    if (V2Size <= 1 && V1Size <= 1)  // Just pointer check?
+      return NoAlias;
 
-          // Otherwise we have to check to see that the distance is more than
-          // the size of the argument... build an index vector that is equal to
-          // the arguments provided, except substitute 0's for any variable
-          // indexes we find...
-          if (TD && cast<PointerType>(
-                BasePtr->getType())->getElementType()->isSized()) {
-            for (unsigned i = 0; i != GEPOperands.size(); ++i)
-              if (!isa<ConstantInt>(GEPOperands[i]))
-                GEPOperands[i] =
-                  Constant::getNullValue(GEPOperands[i]->getType());
-            int64_t Offset =
-              TD->getIndexedOffset(BasePtr->getType(),
-                                   &GEPOperands[0],
-                                   GEPOperands.size());
+    // Otherwise we have to check to see that the distance is more than
+    // the size of the argument... build an index vector that is equal to
+    // the arguments provided, except substitute 0's for any variable
+    // indexes we find...
+    if (TD &&
+        cast<PointerType>(BasePtr->getType())->getElementType()->isSized()) {
+      for (unsigned i = 0; i != GEPOperands.size(); ++i)
+        if (!isa<ConstantInt>(GEPOperands[i]))
+          GEPOperands[i] = Constant::getNullValue(GEPOperands[i]->getType());
+      int64_t Offset = TD->getIndexedOffset(BasePtr->getType(),
+                                            &GEPOperands[0],
+                                            GEPOperands.size());
 
-            if (Offset >= (int64_t)V2Size || Offset <= -(int64_t)V1Size)
-              return NoAlias;
-          }
-        }
-      }
+      if (Offset >= (int64_t)V2Size || Offset <= -(int64_t)V1Size)
+        return NoAlias;
     }
+  }
+
+  return MayAlias;
+}
+
+// aliasPHI - Provide a bunch of ad-hoc rules to disambiguate a PHI instruction
+// against another.
+AliasAnalysis::AliasResult
+BasicAliasAnalysis::aliasPHI(const PHINode *PN, unsigned PNSize,
+                             const Value *V2, unsigned V2Size) {
+  // The PHI node has already been visited, avoid recursion any further.
+  if (!VisitedPHIs.insert(PN))
+    return MayAlias;
+
+  SmallSet<Value*, 4> UniqueSrc;
+  SmallVector<Value*, 4> V1Srcs;
+  for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
+    Value *PV1 = PN->getIncomingValue(i);
+    if (isa<PHINode>(PV1))
+      // If any of the source itself is a PHI, return MayAlias conservatively
+      // to avoid compile time explosion. The worst possible case is if both
+      // sides are PHI nodes. In which case, this is O(m x n) time where 'm'
+      // and 'n' are the number of PHI sources.
+      return MayAlias;
+    if (UniqueSrc.insert(PV1))
+      V1Srcs.push_back(PV1);
+  }
+
+  AliasResult Alias = aliasCheck(V1Srcs[0], PNSize, V2, V2Size);
+  // Early exit if the check of the first PHI source against V2 is MayAlias.
+  // Other results are not possible.
+  if (Alias == MayAlias)
+    return MayAlias;
+
+  // If all sources of the PHI node NoAlias or MustAlias V2, then returns
+  // NoAlias / MustAlias. Otherwise, returns MayAlias.
+  for (unsigned i = 1, e = V1Srcs.size(); i != e; ++i) {
+    Value *V = V1Srcs[i];
+    AliasResult ThisAlias = aliasCheck(V, PNSize, V2, V2Size);
+    if (ThisAlias != Alias || ThisAlias == MayAlias)
+      return MayAlias;
+  }
+
+  return Alias;
+}
+
+// aliasCheck - Provide a bunch of ad-hoc rules to disambiguate in common cases,
+// such as array references.
+//
+AliasAnalysis::AliasResult
+BasicAliasAnalysis::aliasCheck(const Value *V1, unsigned V1Size,
+                               const Value *V2, unsigned V2Size) {
+  // Strip off any casts if they exist.
+  V1 = V1->stripPointerCasts();
+  V2 = V2->stripPointerCasts();
+
+  // Are we checking for alias of the same value?
+  if (V1 == V2) return MustAlias;
+
+  if (!isa<PointerType>(V1->getType()) || !isa<PointerType>(V2->getType()))
+    return NoAlias;  // Scalars cannot alias each other
+
+  // Figure out what objects these things are pointing to if we can.
+  const Value *O1 = V1->getUnderlyingObject();
+  const Value *O2 = V2->getUnderlyingObject();
+
+  if (O1 != O2) {
+    // If V1/V2 point to two different objects we know that we have no alias.
+    if (isIdentifiedObject(O1) && isIdentifiedObject(O2))
+      return NoAlias;
+  
+    // Arguments can't alias with local allocations or noalias calls.
+    if ((isa<Argument>(O1) && (isa<AllocationInst>(O2) || isNoAliasCall(O2))) ||
+        (isa<Argument>(O2) && (isa<AllocationInst>(O1) || isNoAliasCall(O1))))
+      return NoAlias;
+
+    // Most objects can't alias null.
+    if ((isa<ConstantPointerNull>(V2) && isKnownNonNull(O1)) ||
+        (isa<ConstantPointerNull>(V1) && isKnownNonNull(O2)))
+      return NoAlias;
+  }
+  
+  // If the size of one access is larger than the entire object on the other
+  // side, then we know such behavior is undefined and can assume no alias.
+  LLVMContext &Context = V1->getContext();
+  if (TD)
+    if ((V1Size != ~0U && isObjectSmallerThan(O2, V1Size, Context, *TD)) ||
+        (V2Size != ~0U && isObjectSmallerThan(O1, V2Size, Context, *TD)))
+      return NoAlias;
+  
+  // If one pointer is the result of a call/invoke and the other is a
+  // non-escaping local object, then we know the object couldn't escape to a
+  // point where the call could return it.
+  if ((isa<CallInst>(O1) || isa<InvokeInst>(O1)) &&
+      isNonEscapingLocalObject(O2) && O1 != O2)
+    return NoAlias;
+  if ((isa<CallInst>(O2) || isa<InvokeInst>(O2)) &&
+      isNonEscapingLocalObject(O1) && O1 != O2)
+    return NoAlias;
+
+  if (!isGEP(V1) && isGEP(V2)) {
+    std::swap(V1, V2);
+    std::swap(V1Size, V2Size);
+  }
+  if (isGEP(V1))
+    return aliasGEP(V1, V1Size, V2, V2Size);
+
+  if (isa<PHINode>(V2) && !isa<PHINode>(V1)) {
+    std::swap(V1, V2);
+    std::swap(V1Size, V2Size);
+  }
+  if (const PHINode *PN = dyn_cast<PHINode>(V1))
+    return aliasPHI(PN, V1Size, V2, V2Size);
 
   return MayAlias;
 }

Copied: llvm/branches/Apple/Leela/test/Analysis/BasicAA/phi-aa.ll (from r84038, llvm/trunk/test/Analysis/BasicAA/phi-aa.ll)
URL: http://llvm.org/viewvc/llvm-project/llvm/branches/Apple/Leela/test/Analysis/BasicAA/phi-aa.ll?p2=llvm/branches/Apple/Leela/test/Analysis/BasicAA/phi-aa.ll&p1=llvm/trunk/test/Analysis/BasicAA/phi-aa.ll&r1=84038&r2=84104&rev=84104&view=diff

==============================================================================
--- llvm/trunk/test/Analysis/BasicAA/phi-aa.ll (original)
+++ llvm/branches/Apple/Leela/test/Analysis/BasicAA/phi-aa.ll Wed Oct 14 10:55:02 2009
@@ -1,86 +1,29 @@
-; RUN: opt < %s -basicaa -licm -S | FileCheck %s
+; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output |& grep {NoAlias:.*%P,.*@Z}
 ; rdar://7282591
 
-%struct.CFRuntimeBase = type { i32, [4 x i8] }
-%struct.XXXAffineTransform = type { float, float, float, float, float, float }
-%struct.XXXContext = type { %struct.CFRuntimeBase, i32, i32, i32, i8*, %struct.XXXContextDelegate*, void (%struct.XXXContext*)*, void (%struct.XXXContext*)*, %struct.XXXImage* (%struct.XXXContext*, %struct.XXXRect*, %struct.XXXImage*, i8*)*, i8*, %struct.__CFDictionary*, i32, %struct.XXXGState*, %struct.XXXGStack*, %struct.XXXRenderingState*, %struct.XXXAffineTransform, %struct.XXXPath*, %struct.__CFDictionary*, %struct.XXXPixelAccess* }
-%struct.XXXContextDelegate = type opaque
-%struct.XXXGStack = type opaque
-%struct.XXXGState = type opaque
-%struct.XXXImage = type opaque
-%struct.XXXPath = type opaque
-%struct.XXXPixelAccess = type opaque
-%struct.XXXPoint = type { float, float }
-%struct.XXXRect = type { %struct.XXXPoint, %struct.XXXPoint }
-%struct.XXXRenderingState = type opaque
-%struct.__CFDictionary = type opaque
-
-define void @t(%struct.XXXContext* %context, i16* %glyphs, %struct.XXXPoint* %advances, i32 %count) nounwind optsize ssp {
-; CHECK: @t
-; CHECK: bb21.preheader:
-; CHECK: %tmp28 = getelementptr
-; CHECK: %tmp28.promoted = load
-entry:
-  br i1 undef, label %bb1, label %bb
-
-bb:                                               ; preds = %entry
-  br i1 undef, label %bb2, label %bb1
-
-bb1:                                              ; preds = %bb, %entry
-  ret void
-
-bb2:                                              ; preds = %bb
-  br i1 undef, label %bb35, label %bb7
+ at X = common global i32 0
+ at Y = common global i32 0
+ at Z = common global i32 0
 
-bb7:                                              ; preds = %bb2
-  br i1 undef, label %bb35, label %bb10
-
-bb10:                                             ; preds = %bb7
-  %tmp18 = alloca i8, i32 undef, align 1          ; <i8*> [#uses=1]
-  br i1 undef, label %bb35, label %bb15
-
-bb15:                                             ; preds = %bb10
-  br i1 undef, label %bb17, label %bb16
-
-bb16:                                             ; preds = %bb15
-  %tmp21 = bitcast i8* %tmp18 to %struct.XXXPoint* ; <%struct.XXXPoint*> [#uses=1]
-  br label %bb18
-
-bb17:                                             ; preds = %bb15
-  %tmp22 = malloc %struct.XXXPoint, i32 %count     ; <%struct.XXXPoint*> [#uses=1]
-  br label %bb18
-
-bb18:                                             ; preds = %bb17, %bb16
-  %positions.0 = phi %struct.XXXPoint* [ %tmp21, %bb16 ], [ %tmp22, %bb17 ] ; <%struct.XXXPoint*> [#uses=1]
-  br i1 undef, label %bb35, label %bb20
-
-bb20:                                             ; preds = %bb18
-  br i1 undef, label %bb21, label %bb25
-
-bb21:                                             ; preds = %bb21, %bb20
-  %tmp28 = getelementptr inbounds %struct.XXXPoint* %positions.0, i32 undef, i32 0 ; <float*> [#uses=1]
-  store float undef, float* %tmp28, align 4
-  %elt22 = getelementptr inbounds %struct.XXXPoint* %advances, i32 undef, i32 1 ; <float*> [#uses=1]
-  %val23 = load float* %elt22                     ; <float> [#uses=0]
-  br i1 undef, label %bb21, label %bb25
-
-bb25:                                             ; preds = %bb21, %bb20
-  switch i32 undef, label %bb26 [
-    i32 4, label %bb27
-    i32 5, label %bb27
-    i32 6, label %bb27
-    i32 7, label %bb28
-  ]
-
-bb26:                                             ; preds = %bb25
-  unreachable
-
-bb27:                                             ; preds = %bb25, %bb25, %bb25
-  unreachable
-
-bb28:                                             ; preds = %bb25
-  unreachable
+define void @foo(i32 %cond) nounwind ssp {
+entry:
+  %"alloca point" = bitcast i32 0 to i32
+  %tmp = icmp ne i32 %cond, 0
+  br i1 %tmp, label %bb, label %bb1
+
+bb:
+  br label %bb2
+
+bb1:
+  br label %bb2
+
+bb2:
+  %P = phi i32* [ @X, %bb ], [ @Y, %bb1 ]
+  %tmp1 = load i32* @Z, align 4
+  store i32 123, i32* %P, align 4
+  %tmp2 = load i32* @Z, align 4
+  br label %return
 
-bb35:                                             ; preds = %bb18, %bb10, %bb7, %bb2
+return:
   ret void
 }





More information about the llvm-branch-commits mailing list