[llvm] 477e8e1 - [Attributor] Teach AAPointerInfo to look into aggregates

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 5 06:44:35 PDT 2022


Author: Johannes Doerfert
Date: 2022-10-05T06:19:47-07:00
New Revision: 477e8e10f08eae8a9bbf75a46cf6e5d9d4f579f7

URL: https://github.com/llvm/llvm-project/commit/477e8e10f08eae8a9bbf75a46cf6e5d9d4f579f7
DIFF: https://github.com/llvm/llvm-project/commit/477e8e10f08eae8a9bbf75a46cf6e5d9d4f579f7.diff

LOG: [Attributor] Teach AAPointerInfo to look into aggregates

If we have a constant aggregate, e.g., as an initializer, we usually
failed to extract the proper value/type from it. This patch provides the
size and offset information necessary to extract the right part of the
constant.

Added: 
    llvm/test/Transforms/Attributor/value-simplify-pointer-info-struct.ll

Modified: 
    llvm/include/llvm/Transforms/IPO/Attributor.h
    llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp
    llvm/lib/Transforms/IPO/Attributor.cpp
    llvm/lib/Transforms/IPO/AttributorAttributes.cpp
    llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll
    llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll
    llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index c9aa7419dec40..d6cdad242ced0 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -209,9 +209,63 @@ Optional<Value *>
 combineOptionalValuesInAAValueLatice(const Optional<Value *> &A,
                                      const Optional<Value *> &B, Type *Ty);
 
+/// Helper to represent an access offset and size, with logic to deal with
+/// uncertainty and check for overlapping accesses.
+struct OffsetAndSize : public std::pair<int64_t, int64_t> {
+  using BaseTy = std::pair<int64_t, int64_t>;
+  OffsetAndSize(int64_t Offset, int64_t Size) : BaseTy(Offset, Size) {}
+  OffsetAndSize(const BaseTy &P) : BaseTy(P) {}
+  int64_t getOffset() const { return first; }
+  int64_t getSize() const { return second; }
+  static OffsetAndSize getUnknown() { return OffsetAndSize(Unknown, Unknown); }
+  static OffsetAndSize getUnassigned() {
+    return OffsetAndSize(Unassigned, Unassigned);
+  }
+
+  /// Return true if offset or size are unknown.
+  bool offsetOrSizeAreUnknown() const {
+    return getOffset() == OffsetAndSize::Unknown ||
+           getSize() == OffsetAndSize::Unknown;
+  }
+
+  /// Return true if offset and size are unknown, thus this is the default
+  /// unknown object.
+  bool offsetAndSizeAreUnknown() const {
+    return getOffset() == OffsetAndSize::Unknown &&
+           getSize() == OffsetAndSize::Unknown;
+  }
+
+  /// Return true if the offset and size are unassigned.
+  bool isUnassigned() const {
+    assert((getOffset() == OffsetAndSize::Unassigned) ==
+               (getSize() == OffsetAndSize::Unassigned) &&
+           "Inconsistent state!");
+    return getOffset() == OffsetAndSize::Unassigned;
+  }
+
+  /// Return true if this offset and size pair might describe an address that
+  /// overlaps with \p OAS.
+  bool mayOverlap(const OffsetAndSize &OAS) const {
+    // Any unknown value and we are giving up -> overlap.
+    if (offsetOrSizeAreUnknown() || OAS.offsetOrSizeAreUnknown())
+      return true;
+
+    // Check if one offset point is in the other interval [offset,
+    // offset+size].
+    return OAS.getOffset() + OAS.getSize() > getOffset() &&
+           OAS.getOffset() < getOffset() + getSize();
+  }
+
+  /// Constants used to represent special offsets or sizes.
+  static constexpr int64_t Unassigned = -1;
+  static constexpr int64_t Unknown = -2;
+};
+
 /// Return the initial value of \p Obj with type \p Ty if that is a constant.
 Constant *getInitialValueForObj(Value &Obj, Type &Ty,
-                                const TargetLibraryInfo *TLI);
+                                const TargetLibraryInfo *TLI,
+                                const DataLayout &DL,
+                                OffsetAndSize *OASPtr = nullptr);
 
 /// Collect all potential underlying objects of \p Ptr at position \p CtxI in
 /// \p Objects. Assumed information is used and dependences onto \p QueryingAA
@@ -5036,48 +5090,13 @@ struct AAPointerInfo : public AbstractAttribute {
   /// See AbstractAttribute::getIdAddr()
   const char *getIdAddr() const override { return &ID; }
 
-  /// Helper to represent an access offset and size, with logic to deal with
-  /// uncertainty and check for overlapping accesses.
-  struct OffsetAndSize : public std::pair<int64_t, int64_t> {
-    using BaseTy = std::pair<int64_t, int64_t>;
-    OffsetAndSize(int64_t Offset, int64_t Size) : BaseTy(Offset, Size) {}
-    OffsetAndSize(const BaseTy &P) : BaseTy(P) {}
-    int64_t getOffset() const { return first; }
-    int64_t getSize() const { return second; }
-    static OffsetAndSize getUnknown() {
-      return OffsetAndSize(Unknown, Unknown);
-    }
-
-    /// Return true if offset or size are unknown.
-    bool offsetOrSizeAreUnknown() const {
-      return getOffset() == OffsetAndSize::Unknown ||
-             getSize() == OffsetAndSize::Unknown;
-    }
-
-    /// Return true if this offset and size pair might describe an address that
-    /// overlaps with \p OAS.
-    bool mayOverlap(const OffsetAndSize &OAS) const {
-      // Any unknown value and we are giving up -> overlap.
-      if (offsetOrSizeAreUnknown() || OAS.offsetOrSizeAreUnknown())
-        return true;
-
-      // Check if one offset point is in the other interval [offset,
-      // offset+size].
-      return OAS.getOffset() + OAS.getSize() > getOffset() &&
-             OAS.getOffset() < getOffset() + getSize();
-    }
-
-    /// Constants used to represent special offsets or sizes.
-    static constexpr int64_t Unassigned = -1;
-    static constexpr int64_t Unknown = -2;
-  };
-
   /// Call \p CB on all accesses that might interfere with \p OAS and return
   /// true if all such accesses were known and the callback returned true for
   /// all of them, false otherwise. An access interferes with an offset-size
   /// pair if it might read or write that memory region.
   virtual bool forallInterferingAccesses(
-      OffsetAndSize OAS, function_ref<bool(const Access &, bool)> CB) const = 0;
+      AA::OffsetAndSize OAS,
+      function_ref<bool(const Access &, bool)> CB) const = 0;
 
   /// Call \p CB on all accesses that might interfere with \p I and
   /// return true if all such accesses were known and the callback returned true
@@ -5086,11 +5105,10 @@ struct AAPointerInfo : public AbstractAttribute {
   /// affect the load even if they on the surface look as if they would. The
   /// flag \p HasBeenWrittenTo will be set to true if we know that \p I does not
   /// read the intial value of the underlying memory.
-  virtual bool
-  forallInterferingAccesses(Attributor &A, const AbstractAttribute &QueryingAA,
-                            Instruction &I,
-                            function_ref<bool(const Access &, bool)> CB,
-                            bool &HasBeenWrittenTo) const = 0;
+  virtual bool forallInterferingAccesses(
+      Attributor &A, const AbstractAttribute &QueryingAA, Instruction &I,
+      function_ref<bool(const Access &, bool)> CB, bool &HasBeenWrittenTo,
+      AA::OffsetAndSize *OASPtr = nullptr) const = 0;
 
   /// This function should return true if the type of the \p AA is AAPointerInfo
   static bool classof(const AbstractAttribute *AA) {

diff  --git a/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp
index a3634d2440c3d..22cda5c120c8a 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp
@@ -547,32 +547,32 @@ struct AAAMDAttributesFunction : public AAAMDAttributes {
 
   bool funcRetrievesMultigridSyncArg(Attributor &A) {
     auto Pos = llvm::AMDGPU::getMultigridSyncArgImplicitArgPosition();
-    AAPointerInfo::OffsetAndSize OAS(Pos, 8);
+    AA::OffsetAndSize OAS(Pos, 8);
     return funcRetrievesImplicitKernelArg(A, OAS);
   }
 
   bool funcRetrievesHostcallPtr(Attributor &A) {
     auto Pos = llvm::AMDGPU::getHostcallImplicitArgPosition();
-    AAPointerInfo::OffsetAndSize OAS(Pos, 8);
+    AA::OffsetAndSize OAS(Pos, 8);
     return funcRetrievesImplicitKernelArg(A, OAS);
   }
 
   bool funcRetrievesHeapPtr(Attributor &A) {
     if (AMDGPU::getAmdhsaCodeObjectVersion() != 5)
       return false;
-    AAPointerInfo::OffsetAndSize OAS(AMDGPU::ImplicitArg::HEAP_PTR_OFFSET, 8);
+    AA::OffsetAndSize OAS(AMDGPU::ImplicitArg::HEAP_PTR_OFFSET, 8);
     return funcRetrievesImplicitKernelArg(A, OAS);
   }
 
   bool funcRetrievesQueuePtr(Attributor &A) {
     if (AMDGPU::getAmdhsaCodeObjectVersion() != 5)
       return false;
-    AAPointerInfo::OffsetAndSize OAS(AMDGPU::ImplicitArg::QUEUE_PTR_OFFSET, 8);
+    AA::OffsetAndSize OAS(AMDGPU::ImplicitArg::QUEUE_PTR_OFFSET, 8);
     return funcRetrievesImplicitKernelArg(A, OAS);
   }
 
   bool funcRetrievesImplicitKernelArg(Attributor &A,
-                                      AAPointerInfo::OffsetAndSize OAS) {
+                                      AA::OffsetAndSize OAS) {
     // Check if this is a call to the implicitarg_ptr builtin and it
     // is used to retrieve the hostcall pointer. The implicit arg for
     // hostcall is not used only if every use of the implicitarg_ptr

diff  --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index fdbed1b62fdcd..4e6a13913c9d2 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -27,7 +27,9 @@
 #include "llvm/Analysis/MustExecute.h"
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/Constant.h"
+#include "llvm/IR/ConstantFold.h"
 #include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
 #include "llvm/IR/GlobalValue.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/Instruction.h"
@@ -45,6 +47,7 @@
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 #include "llvm/Transforms/Utils/Cloning.h"
 #include "llvm/Transforms/Utils/Local.h"
+#include <cstdint>
 
 #ifdef EXPENSIVE_CHECKS
 #include "llvm/IR/Verifier.h"
@@ -219,7 +222,9 @@ bool AA::isDynamicallyUnique(Attributor &A, const AbstractAttribute &QueryingAA,
 }
 
 Constant *AA::getInitialValueForObj(Value &Obj, Type &Ty,
-                                    const TargetLibraryInfo *TLI) {
+                                    const TargetLibraryInfo *TLI,
+                                    const DataLayout &DL,
+                                    AA::OffsetAndSize *OASPtr) {
   if (isa<AllocaInst>(Obj))
     return UndefValue::get(&Ty);
   if (Constant *Init = getInitialValueOfAllocation(&Obj, TLI, &Ty))
@@ -231,7 +236,25 @@ Constant *AA::getInitialValueForObj(Value &Obj, Type &Ty,
     return nullptr;
   if (!GV->hasInitializer())
     return UndefValue::get(&Ty);
-  return dyn_cast_or_null<Constant>(getWithType(*GV->getInitializer(), Ty));
+
+  // Handle constant initializers by extracting the relevant parts for
+  // aggregates.
+  Constant *C = GV->getInitializer();
+  if (OASPtr && !OASPtr->offsetOrSizeAreUnknown() &&
+      isa<ConstantAggregate>(C)) {
+    Type *CTy = C->getType();
+    APInt Offset = APInt(64, OASPtr->getOffset());
+    Optional<APInt> Idx = DL.getGEPIndexForOffset(CTy, Offset);
+    // Check if the indexing worked out properly.
+    // TODO: Handle partial accesses, e.g., Offset is > 0 or Size < CTy.size().
+    if (Idx && Offset.isZero() &&
+        DL.getTypeSizeInBits(CTy) == uint64_t(OASPtr->getSize() * 8)) {
+      if (auto *Folded =
+              ConstantFoldExtractValueInstruction(C, Idx->getZExtValue()))
+        C = Folded;
+    }
+  }
+  return dyn_cast_or_null<Constant>(getWithType(*C, Ty));
 }
 
 bool AA::isValidInScope(const Value &V, const Function *Scope) {
@@ -441,10 +464,11 @@ static bool getPotentialCopiesOfMemoryValue(
     // object.
     bool HasBeenWrittenTo = false;
 
+    AA::OffsetAndSize OAS = AA::OffsetAndSize::getUnassigned();
     auto &PI = A.getAAFor<AAPointerInfo>(QueryingAA, IRPosition::value(*Obj),
                                          DepClassTy::NONE);
     if (!PI.forallInterferingAccesses(A, QueryingAA, I, CheckAccess,
-                                      HasBeenWrittenTo)) {
+                                      HasBeenWrittenTo, &OAS)) {
       LLVM_DEBUG(
           dbgs()
           << "Failed to verify all interfering accesses for underlying object: "
@@ -452,10 +476,15 @@ static bool getPotentialCopiesOfMemoryValue(
       return false;
     }
 
-    if (IsLoad && !HasBeenWrittenTo) {
-      Value *InitialValue = AA::getInitialValueForObj(*Obj, *I.getType(), TLI);
-      if (!InitialValue)
+    if (IsLoad && !HasBeenWrittenTo && !OAS.isUnassigned()) {
+      const DataLayout &DL = A.getDataLayout();
+      Value *InitialValue =
+          AA::getInitialValueForObj(*Obj, *I.getType(), TLI, DL, &OAS);
+      if (!InitialValue) {
+        LLVM_DEBUG(dbgs() << "Could not determine required initial value of "
+                             "underlying object, abort!\n");
         return false;
+      }
       CheckForNullOnlyAndUndef(InitialValue, /* IsExact */ true);
       if (NullRequired && !NullOnly) {
         LLVM_DEBUG(dbgs() << "Non exact access but initial value that is not "
@@ -593,8 +622,7 @@ isPotentiallyReachable(Attributor &A, const Instruction &FromI,
     // Check if the current instruction is already known to reach the ToFn.
     const auto &FnReachabilityAA = A.getAAFor<AAFunctionReachability>(
         QueryingAA, IRPosition::function(*FromFn), DepClassTy::OPTIONAL);
-    bool Result = FnReachabilityAA.instructionCanReach(
-        A, *CurFromI, ToFn);
+    bool Result = FnReachabilityAA.instructionCanReach(A, *CurFromI, ToFn);
     LLVM_DEBUG(dbgs() << "[AA] " << *CurFromI << " in @" << FromFn->getName()
                       << " " << (Result ? "can potentially " : "cannot ")
                       << "reach @" << ToFn.getName() << " [FromFn]\n");

diff  --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 6986a6d679343..8744003a7b5fd 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -720,7 +720,7 @@ struct DenseMapInfo<AAPointerInfo::Access> : DenseMapInfo<Instruction *> {
 
 /// Helper that allows OffsetAndSize as a key in a DenseMap.
 template <>
-struct DenseMapInfo<AAPointerInfo ::OffsetAndSize>
+struct DenseMapInfo<AA::OffsetAndSize>
     : DenseMapInfo<std::pair<int64_t, int64_t>> {};
 
 /// Helper for AA::PointerInfo::Access DenseMap/Set usage ignoring everythign
@@ -847,7 +847,7 @@ struct AA::PointerInfo::State : public AbstractState {
   };
 
   /// We store all accesses in bins denoted by their offset and size.
-  using AccessBinsTy = DenseMap<AAPointerInfo::OffsetAndSize, Accesses *>;
+  using AccessBinsTy = DenseMap<AA::OffsetAndSize, Accesses *>;
 
   AccessBinsTy::const_iterator begin() const { return AccessBins.begin(); }
   AccessBinsTy::const_iterator end() const { return AccessBins.end(); }
@@ -865,7 +865,7 @@ struct AA::PointerInfo::State : public AbstractState {
                          AAPointerInfo::AccessKind Kind, Type *Ty,
                          Instruction *RemoteI = nullptr,
                          Accesses *BinPtr = nullptr) {
-    AAPointerInfo::OffsetAndSize Key{Offset, Size};
+    AA::OffsetAndSize Key{Offset, Size};
     Accesses *&Bin = BinPtr ? BinPtr : AccessBins[Key];
     if (!Bin)
       Bin = new (A.Allocator) Accesses;
@@ -887,13 +887,13 @@ struct AA::PointerInfo::State : public AbstractState {
 
   /// See AAPointerInfo::forallInterferingAccesses.
   bool forallInterferingAccesses(
-      AAPointerInfo::OffsetAndSize OAS,
+      AA::OffsetAndSize OAS,
       function_ref<bool(const AAPointerInfo::Access &, bool)> CB) const {
     if (!isValidState())
       return false;
 
     for (const auto &It : AccessBins) {
-      AAPointerInfo::OffsetAndSize ItOAS = It.getFirst();
+      AA::OffsetAndSize ItOAS = It.getFirst();
       if (!OAS.mayOverlap(ItOAS))
         continue;
       bool IsExact = OAS == ItOAS && !OAS.offsetOrSizeAreUnknown();
@@ -907,12 +907,13 @@ struct AA::PointerInfo::State : public AbstractState {
   /// See AAPointerInfo::forallInterferingAccesses.
   bool forallInterferingAccesses(
       Instruction &I,
-      function_ref<bool(const AAPointerInfo::Access &, bool)> CB) const {
+      function_ref<bool(const AAPointerInfo::Access &, bool)> CB,
+      AA::OffsetAndSize *OASPtr) const {
     if (!isValidState())
       return false;
 
     // First find the offset and size of I.
-    AAPointerInfo::OffsetAndSize OAS(-1, -1);
+    AA::OffsetAndSize OAS = AA::OffsetAndSize::getUnassigned();
     for (const auto &It : AccessBins) {
       for (auto &Access : *It.getSecond()) {
         if (Access.getRemoteInst() == &I) {
@@ -920,11 +921,15 @@ struct AA::PointerInfo::State : public AbstractState {
           break;
         }
       }
-      if (OAS.getSize() != -1)
+      if (OAS.getSize() != AA::OffsetAndSize::Unassigned)
         break;
     }
+
+    if (OASPtr)
+      *OASPtr = OAS;
+
     // No access for I was found, we are done.
-    if (OAS.getSize() == -1)
+    if (OAS.getSize() == AA::OffsetAndSize::Unassigned)
       return true;
 
     // Now that we have an offset and size, find all overlapping ones and use
@@ -957,17 +962,16 @@ struct AAPointerInfoImpl
   }
 
   bool forallInterferingAccesses(
-      OffsetAndSize OAS,
+      AA::OffsetAndSize OAS,
       function_ref<bool(const AAPointerInfo::Access &, bool)> CB)
       const override {
     return State::forallInterferingAccesses(OAS, CB);
   }
 
-  bool
-  forallInterferingAccesses(Attributor &A, const AbstractAttribute &QueryingAA,
-                            Instruction &I,
-                            function_ref<bool(const Access &, bool)> UserCB,
-                            bool &HasBeenWrittenTo) const override {
+  bool forallInterferingAccesses(
+      Attributor &A, const AbstractAttribute &QueryingAA, Instruction &I,
+      function_ref<bool(const Access &, bool)> UserCB, bool &HasBeenWrittenTo,
+      AA::OffsetAndSize *OASPtr = nullptr) const override {
     HasBeenWrittenTo = false;
 
     SmallPtrSet<const Access *, 8> DominatingWrites;
@@ -1082,7 +1086,7 @@ struct AAPointerInfoImpl
       InterferingAccesses.push_back({&Acc, Exact});
       return true;
     };
-    if (!State::forallInterferingAccesses(I, AccessCB))
+    if (!State::forallInterferingAccesses(I, AccessCB, OASPtr))
       return false;
 
     if (HasBeenWrittenTo) {
@@ -1150,9 +1154,10 @@ struct AAPointerInfoImpl
     // Combine the accesses bin by bin.
     ChangeStatus Changed = ChangeStatus::UNCHANGED;
     for (const auto &It : OtherAAImpl.getState()) {
-      OffsetAndSize OAS = OffsetAndSize::getUnknown();
-      if (Offset != OffsetAndSize::Unknown)
-        OAS = OffsetAndSize(It.first.getOffset() + Offset, It.first.getSize());
+      AA::OffsetAndSize OAS = AA::OffsetAndSize::getUnknown();
+      if (Offset != AA::OffsetAndSize::Unknown)
+        OAS = AA::OffsetAndSize(It.first.getOffset() + Offset,
+                                It.first.getSize());
       Accesses *Bin = AccessBins.lookup(OAS);
       for (const AAPointerInfo::Access &RAcc : *It.second) {
         if (IsByval && !RAcc.isRead())
@@ -1210,11 +1215,10 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
   bool handleAccess(Attributor &A, Instruction &I, Value &Ptr,
                     Optional<Value *> Content, AccessKind Kind, int64_t Offset,
                     ChangeStatus &Changed, Type *Ty,
-                    int64_t Size = OffsetAndSize::Unknown) {
+                    int64_t Size = AA::OffsetAndSize::Unknown) {
     using namespace AA::PointerInfo;
-    // No need to find a size if one is given or the offset is unknown.
-    if (Offset != OffsetAndSize::Unknown && Size == OffsetAndSize::Unknown &&
-        Ty) {
+    // No need to find a size if one is given.
+    if (Size == AA::OffsetAndSize::Unknown && Ty) {
       const DataLayout &DL = A.getDataLayout();
       TypeSize AccessSize = DL.getTypeStoreSize(Ty);
       if (!AccessSize.isScalable())
@@ -1226,7 +1230,7 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
 
   /// Helper struct, will support ranges eventually.
   struct OffsetInfo {
-    int64_t Offset = OffsetAndSize::Unassigned;
+    int64_t Offset = AA::OffsetAndSize::Unassigned;
 
     bool operator==(const OffsetInfo &OI) const { return Offset == OI.Offset; }
   };
@@ -1243,7 +1247,7 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
 
     auto HandlePassthroughUser = [&](Value *Usr, OffsetInfo PtrOI,
                                      bool &Follow) {
-      assert(PtrOI.Offset != OffsetAndSize::Unassigned &&
+      assert(PtrOI.Offset != AA::OffsetAndSize::Unassigned &&
              "Cannot pass through if the input Ptr was not visited!");
       OffsetInfo &UsrOI = OffsetInfoMap[Usr];
       UsrOI = PtrOI;
@@ -1283,11 +1287,11 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
 
         // TODO: Use range information.
         APInt GEPOffset(DL.getIndexTypeSizeInBits(GEP->getType()), 0);
-        if (PtrOI.Offset == OffsetAndSize::Unknown ||
+        if (PtrOI.Offset == AA::OffsetAndSize::Unknown ||
             !GEP->accumulateConstantOffset(DL, GEPOffset)) {
           LLVM_DEBUG(dbgs() << "[AAPointerInfo] GEP offset not constant "
                             << *GEP << "\n");
-          UsrOI.Offset = OffsetAndSize::Unknown;
+          UsrOI.Offset = AA::OffsetAndSize::Unknown;
           Follow = true;
           return true;
         }
@@ -1315,17 +1319,17 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
 
         // Check if the PHI operand has already an unknown offset as we can't
         // improve on that anymore.
-        if (PtrOI.Offset == OffsetAndSize::Unknown) {
+        if (PtrOI.Offset == AA::OffsetAndSize::Unknown) {
           LLVM_DEBUG(dbgs() << "[AAPointerInfo] PHI operand offset unknown "
                             << *CurPtr << " in " << *Usr << "\n");
-          Follow = UsrOI.Offset != OffsetAndSize::Unknown;
+          Follow = UsrOI.Offset != AA::OffsetAndSize::Unknown;
           UsrOI = PtrOI;
           return true;
         }
 
         // Check if the PHI is invariant (so far).
         if (UsrOI == PtrOI) {
-          assert(PtrOI.Offset != OffsetAndSize::Unassigned &&
+          assert(PtrOI.Offset != AA::OffsetAndSize::Unassigned &&
                  "Cannot assign if the current Ptr was not visited!");
           LLVM_DEBUG(dbgs() << "[AAPointerInfo] PHI is invariant (so far)");
           return true;
@@ -1352,7 +1356,7 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
 
         // TODO: Approximate in case we know the direction of the recurrence.
         UsrOI = PtrOI;
-        UsrOI.Offset = OffsetAndSize::Unknown;
+        UsrOI.Offset = AA::OffsetAndSize::Unknown;
         Follow = true;
         return true;
       }
@@ -1495,7 +1499,7 @@ struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {
     // accessed.
     if (auto *MI = dyn_cast_or_null<MemIntrinsic>(getCtxI())) {
       ConstantInt *Length = dyn_cast<ConstantInt>(MI->getLength());
-      int64_t LengthVal = OffsetAndSize::Unknown;
+      int64_t LengthVal = AA::OffsetAndSize::Unknown;
       if (Length)
         LengthVal = Length->getSExtValue();
       Value &Ptr = getAssociatedValue();

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll
index 35415e40f1031..d08c230e79607 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
 
 %T = type { i32, i32, i32, i32 }
@@ -9,14 +9,11 @@
 ; CHECK: @[[G:[a-zA-Z0-9_$"\\.-]+]] = constant [[T:%.*]] { i32 0, i32 0, i32 17, i32 25 }
 ;.
 define internal i32 @test(%T* %p) {
-; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; CHECK-LABEL: define {{[^@]+}}@test
-; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[A:%.*]] = load i32, i32* getelementptr inbounds ([[T:%.*]], %T* @G, i64 0, i32 3), align 4
-; CHECK-NEXT:    [[B:%.*]] = load i32, i32* getelementptr inbounds ([[T]], %T* @G, i64 0, i32 2), align 8
-; CHECK-NEXT:    [[V:%.*]] = add i32 [[A]], [[B]]
-; CHECK-NEXT:    ret i32 [[V]]
+; CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; CGSCC-LABEL: define {{[^@]+}}@test
+; CGSCC-SAME: () #[[ATTR0:[0-9]+]] {
+; CGSCC-NEXT:  entry:
+; CGSCC-NEXT:    ret i32 42
 ;
 entry:
   %a.gep = getelementptr %T, %T* %p, i64 0, i32 3
@@ -28,18 +25,18 @@ entry:
 }
 
 define i32 @caller() {
+;
 ; TUNIT: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; TUNIT-LABEL: define {{[^@]+}}@caller
-; TUNIT-SAME: () #[[ATTR0]] {
+; TUNIT-SAME: () #[[ATTR0:[0-9]+]] {
 ; TUNIT-NEXT:  entry:
-; TUNIT-NEXT:    [[V:%.*]] = call i32 @test() #[[ATTR1:[0-9]+]]
-; TUNIT-NEXT:    ret i32 [[V]]
+; TUNIT-NEXT:    ret i32 42
 ;
 ; CGSCC: Function Attrs: nofree nosync nounwind readnone willreturn
 ; CGSCC-LABEL: define {{[^@]+}}@caller
 ; CGSCC-SAME: () #[[ATTR1:[0-9]+]] {
 ; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[V:%.*]] = call i32 @test() #[[ATTR2:[0-9]+]]
+; CGSCC-NEXT:    [[V:%.*]] = call noundef i32 @test() #[[ATTR2:[0-9]+]]
 ; CGSCC-NEXT:    ret i32 [[V]]
 ;
 entry:
@@ -48,7 +45,6 @@ entry:
 }
 ;.
 ; TUNIT: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
-; TUNIT: attributes #[[ATTR1]] = { nofree nosync nounwind readnone willreturn }
 ;.
 ; CGSCC: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
 ; CGSCC: attributes #[[ATTR1]] = { nofree nosync nounwind readnone willreturn }

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll
index efffad3b09bca..ad98b8a4eb562 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/fp80.ll
@@ -25,13 +25,10 @@ define void @run() {
 ; TUNIT-NEXT:  entry:
 ; TUNIT-NEXT:    unreachable
 ;
-; CGSCC: Function Attrs: nofree nosync nounwind readonly willreturn
+; CGSCC: Function Attrs: nofree nosync nounwind readnone willreturn
 ; CGSCC-LABEL: define {{[^@]+}}@run
 ; CGSCC-SAME: () #[[ATTR0:[0-9]+]] {
 ; CGSCC-NEXT:  entry:
-; CGSCC-NEXT:    [[TMP0:%.*]] = load i32, i32* getelementptr inbounds ([[STRUCT_FOO:%.*]], %struct.Foo* @a, i32 0, i32 0), align 8
-; CGSCC-NEXT:    [[A_0_1:%.*]] = getelementptr [[STRUCT_FOO]], %struct.Foo* @a, i64 0, i32 1
-; CGSCC-NEXT:    [[TMP1:%.*]] = load i64, i64* [[A_0_1]], align 8
 ; CGSCC-NEXT:    unreachable
 ;
 entry:
@@ -109,7 +106,7 @@ loop:
 ;.
 ; TUNIT: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
 ;.
-; CGSCC: attributes #[[ATTR0]] = { nofree nosync nounwind readonly willreturn }
+; CGSCC: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn }
 ; CGSCC: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn }
 ; CGSCC: attributes #[[ATTR2]] = { nofree norecurse noreturn nosync nounwind readnone }
 ;.

diff  --git a/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll b/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll
index 6f0e2dcd0385a..fdcc1f51e481f 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=15 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=16 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
 ;
 ;    void bar(int, float, double);
@@ -107,7 +107,7 @@ define internal void @.omp_outlined.(i32* noalias %.global_tid., i32* noalias %.
 ; TUNIT:       omp.inner.for.body:
 ; TUNIT-NEXT:    [[ADD10:%.*]] = add nsw i32 [[DOTOMP_IV_0]], 2
 ; TUNIT-NEXT:    [[TMP11:%.*]] = load double, double* [[CONV]], align 8
-; TUNIT-NEXT:    call void @bar(i32 [[ADD10]], float 3.000000e+00, double [[TMP11]])
+; TUNIT-NEXT:    call void @bar(i32 [[ADD10]], float 3.000000e+00, double noundef [[TMP11]])
 ; TUNIT-NEXT:    br label [[OMP_BODY_CONTINUE:%.*]]
 ; TUNIT:       omp.body.continue:
 ; TUNIT-NEXT:    br label [[OMP_INNER_FOR_INC]]
@@ -168,7 +168,7 @@ define internal void @.omp_outlined.(i32* noalias %.global_tid., i32* noalias %.
 ; CGSCC-NEXT:    [[ADD10:%.*]] = add nsw i32 [[DOTOMP_IV_0]], 2
 ; CGSCC-NEXT:    [[TMP10:%.*]] = load float, float* [[P]], align 4
 ; CGSCC-NEXT:    [[TMP11:%.*]] = load double, double* [[CONV]], align 8
-; CGSCC-NEXT:    call void @bar(i32 [[ADD10]], float [[TMP10]], double [[TMP11]])
+; CGSCC-NEXT:    call void @bar(i32 [[ADD10]], float [[TMP10]], double noundef [[TMP11]])
 ; CGSCC-NEXT:    br label [[OMP_BODY_CONTINUE:%.*]]
 ; CGSCC:       omp.body.continue:
 ; CGSCC-NEXT:    br label [[OMP_INNER_FOR_INC]]

diff  --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info-struct.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info-struct.ll
new file mode 100644
index 0000000000000..57c0ac8b85adf
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info-struct.ll
@@ -0,0 +1,221 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
+; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=9 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=9 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
+; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
+;
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.S = type { i32, double, ptr }
+
+;    struct S {
+;      int a;
+;      double b;
+;      struct S* c;
+;    };
+;
+;    static const struct S GlobalS = {42, 3.14, 0};
+;
+;    int testOneFieldGlobalS() {
+;      int r = 0;
+;      if (GlobalS.a != 42)
+;        r += 1;
+;      if (GlobalS.b == 3.14)
+;        r += 2;
+;      if (GlobalS.c)
+;        r += 4;
+;      return r;
+;    }
+;
+ at GlobalS = internal constant %struct.S { i32 42, double 3.140000e+00, ptr null }, align 8
+
+;.
+; CHECK: @[[GLOBALS:[a-zA-Z0-9_$"\\.-]+]] = internal constant [[STRUCT_S:%.*]] { i32 42, double 3.140000e+00, ptr null }, align 8
+;.
+define i32 @testOneFieldGlobalS() {
+; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; CHECK-LABEL: define {{[^@]+}}@testOneFieldGlobalS
+; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end:
+; CHECK-NEXT:    br label [[IF_THEN2:%.*]]
+; CHECK:       if.then2:
+; CHECK-NEXT:    [[ADD3:%.*]] = add nsw i32 0, 2
+; CHECK-NEXT:    br label [[IF_END4:%.*]]
+; CHECK:       if.end4:
+; CHECK-NEXT:    br label [[IF_END7:%.*]]
+; CHECK:       if.then5:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end7:
+; CHECK-NEXT:    ret i32 2
+;
+entry:
+  %i = load i32, ptr @GlobalS, align 8
+  %cmp = icmp ne i32 %i, 42
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  %add = add nsw i32 0, 1
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  %r.0 = phi i32 [ %add, %if.then ], [ 0, %entry ]
+  %i1 = load double, ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 1), align 8
+  %cmp1 = fcmp oeq double %i1, 3.140000e+00
+  br i1 %cmp1, label %if.then2, label %if.end4
+
+if.then2:                                         ; preds = %if.end
+  %add3 = add nsw i32 %r.0, 2
+  br label %if.end4
+
+if.end4:                                          ; preds = %if.then2, %if.end
+  %r.1 = phi i32 [ %add3, %if.then2 ], [ %r.0, %if.end ]
+  %i2 = load ptr, ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 2), align 8
+  %tobool = icmp ne ptr %i2, null
+  br i1 %tobool, label %if.then5, label %if.end7
+
+if.then5:                                         ; preds = %if.end4
+  %add6 = add nsw i32 %r.1, 4
+  br label %if.end7
+
+if.end7:                                          ; preds = %if.then5, %if.end4
+  %r.2 = phi i32 [ %add6, %if.then5 ], [ %r.1, %if.end4 ]
+  ret i32 %r.2
+}
+
+define i32 @testOneFieldGlobalS_type_mismatch() {
+; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; CHECK-LABEL: define {{[^@]+}}@testOneFieldGlobalS_type_mismatch
+; CHECK-SAME: () #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[I:%.*]] = load double, ptr @GlobalS, align 8
+; CHECK-NEXT:    [[IC:%.*]] = fptosi double [[I]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[IC]], 42
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 0, 1
+; CHECK-NEXT:    br label [[IF_END]]
+; CHECK:       if.end:
+; CHECK-NEXT:    [[R_0:%.*]] = phi i32 [ [[ADD]], [[IF_THEN]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[I1:%.*]] = load i64, ptr getelementptr inbounds ([[STRUCT_S:%.*]], ptr @GlobalS, i32 0, i32 1), align 8
+; CHECK-NEXT:    [[I1C:%.*]] = sitofp i64 [[I1]] to double
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp oeq double [[I1C]], 3.140000e+00
+; CHECK-NEXT:    br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END4:%.*]]
+; CHECK:       if.then2:
+; CHECK-NEXT:    [[ADD3:%.*]] = add nsw i32 [[R_0]], 2
+; CHECK-NEXT:    br label [[IF_END4]]
+; CHECK:       if.end4:
+; CHECK-NEXT:    [[R_1:%.*]] = phi i32 [ [[ADD3]], [[IF_THEN2]] ], [ [[R_0]], [[IF_END]] ]
+; CHECK-NEXT:    br label [[IF_END7:%.*]]
+; CHECK:       if.then5:
+; CHECK-NEXT:    unreachable
+; CHECK:       if.end7:
+; CHECK-NEXT:    ret i32 [[R_1]]
+;
+entry:
+  %i = load double, ptr @GlobalS, align 8
+  %ic = fptosi double %i to i32
+  %cmp = icmp ne i32 %ic, 42
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  %add = add nsw i32 0, 1
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  %r.0 = phi i32 [ %add, %if.then ], [ 0, %entry ]
+  %i1 = load i64, ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 1), align 8
+  %i1c = sitofp i64 %i1 to double
+  %cmp1 = fcmp oeq double %i1c, 3.140000e+00
+  br i1 %cmp1, label %if.then2, label %if.end4
+
+if.then2:                                         ; preds = %if.end
+  %add3 = add nsw i32 %r.0, 2
+  br label %if.end4
+
+if.end4:                                          ; preds = %if.then2, %if.end
+  %r.1 = phi i32 [ %add3, %if.then2 ], [ %r.0, %if.end ]
+  %i2 = load i64, ptr getelementptr inbounds (%struct.S, ptr @GlobalS, i32 0, i32 2), align 8
+  %i2c = inttoptr i64 %i2 to ptr
+  %tobool = icmp ne ptr %i2c, null
+  br i1 %tobool, label %if.then5, label %if.end7
+
+if.then5:                                         ; preds = %if.end4
+  %add6 = add nsw i32 %r.1, 4
+  br label %if.end7
+
+if.end7:                                          ; preds = %if.then5, %if.end4
+  %r.2 = phi i32 [ %add6, %if.then5 ], [ %r.1, %if.end4 ]
+  ret i32 %r.2
+}
+
+define i32 @testOneFieldGlobalS_byte_offset_wrong() {
+; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; CHECK-LABEL: define {{[^@]+}}@testOneFieldGlobalS_byte_offset_wrong
+; CHECK-SAME: () #[[ATTR0]] {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[I:%.*]] = load i32, ptr getelementptr inbounds (i32, ptr @GlobalS, i32 1), align 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[I]], 42
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 0, 1
+; CHECK-NEXT:    br label [[IF_END]]
+; CHECK:       if.end:
+; CHECK-NEXT:    [[R_0:%.*]] = phi i32 [ [[ADD]], [[IF_THEN]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[I1:%.*]] = load double, ptr getelementptr (double, ptr @GlobalS, i32 3), align 8
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp oeq double [[I1]], 3.140000e+00
+; CHECK-NEXT:    br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END4:%.*]]
+; CHECK:       if.then2:
+; CHECK-NEXT:    [[ADD3:%.*]] = add nsw i32 [[R_0]], 2
+; CHECK-NEXT:    br label [[IF_END4]]
+; CHECK:       if.end4:
+; CHECK-NEXT:    [[R_1:%.*]] = phi i32 [ [[ADD3]], [[IF_THEN2]] ], [ [[R_0]], [[IF_END]] ]
+; CHECK-NEXT:    [[I2:%.*]] = load ptr, ptr getelementptr (ptr, ptr @GlobalS, i32 11), align 8
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne ptr [[I2]], null
+; CHECK-NEXT:    br i1 [[TOBOOL]], label [[IF_THEN5:%.*]], label [[IF_END7:%.*]]
+; CHECK:       if.then5:
+; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[R_1]], 4
+; CHECK-NEXT:    br label [[IF_END7]]
+; CHECK:       if.end7:
+; CHECK-NEXT:    [[R_2:%.*]] = phi i32 [ [[ADD6]], [[IF_THEN5]] ], [ [[R_1]], [[IF_END4]] ]
+; CHECK-NEXT:    ret i32 [[R_2]]
+;
+entry:
+  %i = load i32, ptr getelementptr (i32, ptr @GlobalS, i32 1), align 8
+  %cmp = icmp ne i32 %i, 42
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  %add = add nsw i32 0, 1
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  %r.0 = phi i32 [ %add, %if.then ], [ 0, %entry ]
+  %i1 = load double, ptr getelementptr (double, ptr @GlobalS, i32 3), align 8
+  %cmp1 = fcmp oeq double %i1, 3.140000e+00
+  br i1 %cmp1, label %if.then2, label %if.end4
+
+if.then2:                                         ; preds = %if.end
+  %add3 = add nsw i32 %r.0, 2
+  br label %if.end4
+
+if.end4:                                          ; preds = %if.then2, %if.end
+  %r.1 = phi i32 [ %add3, %if.then2 ], [ %r.0, %if.end ]
+  %i2 = load ptr, ptr getelementptr (ptr, ptr @GlobalS, i32 11), align 8
+  %tobool = icmp ne ptr %i2, null
+  br i1 %tobool, label %if.then5, label %if.end7
+
+if.then5:                                         ; preds = %if.end4
+  %add6 = add nsw i32 %r.1, 4
+  br label %if.end7
+
+if.end7:                                          ; preds = %if.then5, %if.end4
+  %r.2 = phi i32 [ %add6, %if.then5 ], [ %r.1, %if.end4 ]
+  ret i32 %r.2
+}
+;.
+; CHECK: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
+;.


        


More information about the llvm-commits mailing list