[llvm] 0d966ae - [Loads] Add canReplacePointersIfEqual helper.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 1 12:58:02 PDT 2020


Author: Florian Hahn
Date: 2020-09-01T20:57:41+01:00
New Revision: 0d966ae4b2ac0344e15888d0f0a81c322e3d6dd2

URL: https://github.com/llvm/llvm-project/commit/0d966ae4b2ac0344e15888d0f0a81c322e3d6dd2
DIFF: https://github.com/llvm/llvm-project/commit/0d966ae4b2ac0344e15888d0f0a81c322e3d6dd2.diff

LOG: [Loads] Add canReplacePointersIfEqual helper.

This patch adds an initial, incomeplete and unsound implementation of
canReplacePointersIfEqual to check if a pointer value A can be replaced
by another pointer value B, that are deemed to be equivalent through
some means (e.g. information from conditions).

Note that is in general not sound to blindly replace pointers based on
equality, for example if they are based on different underlying objects.

LLVM's memory model is not completely settled as of now; see
https://bugs.llvm.org/show_bug.cgi?id=34548 for a more detailed
discussion.

The initial version of canReplacePointersIfEqual only rejects a very
specific case: replacing a pointer with a constant expression that is
not dereferenceable. Such a replacement is problematic and can be
restricted relatively easily without impacting most code. Using it to
limit replacements in GVN/SCCP/CVP only results in small differences in
7 programs out of MultiSource/SPEC2000/SPEC2006 on X86 with -O3 -flto.

This patch is supposed to be an initial step to improve the current
situation and the helper should be made stricter in the future. But this
will require careful analysis of the impact on performance.

Reviewed By: aqjune

Differential Revision: https://reviews.llvm.org/D85524

Added: 
    

Modified: 
    llvm/include/llvm/Analysis/Loads.h
    llvm/lib/Analysis/Loads.cpp
    llvm/unittests/Analysis/LoadsTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/Loads.h b/llvm/include/llvm/Analysis/Loads.h
index 5665a802942d..24a05610e68d 100644
--- a/llvm/include/llvm/Analysis/Loads.h
+++ b/llvm/include/llvm/Analysis/Loads.h
@@ -155,6 +155,15 @@ Value *FindAvailablePtrLoadStore(Value *Ptr, Type *AccessTy, bool AtLeastAtomic,
                                  BasicBlock::iterator &ScanFrom,
                                  unsigned MaxInstsToScan, AAResults *AA,
                                  bool *IsLoadCSE, unsigned *NumScanedInst);
+
+/// Returns true if a pointer value \p A can be replace with another pointer
+/// value \B if they are deemed equal through some means (e.g. information from
+/// conditions).
+/// NOTE: the current implementations is incomplete and unsound. It does not
+/// reject all invalid cases yet, but will be made stricter in the future. In
+/// particular this means returning true means unknown if replacement is safe.
+bool canReplacePointersIfEqual(Value *A, Value *B, const DataLayout &DL,
+                               Instruction *CtxI);
 }
 
 #endif

diff  --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index e5245225d905..b81322b69bbd 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -503,3 +503,23 @@ Value *llvm::FindAvailablePtrLoadStore(Value *Ptr, Type *AccessTy,
   // block.
   return nullptr;
 }
+
+bool llvm::canReplacePointersIfEqual(Value *A, Value *B, const DataLayout &DL,
+                                     Instruction *CtxI) {
+  Type *Ty = A->getType();
+  assert(Ty == B->getType() && Ty->isPointerTy() &&
+         "values must have matching pointer types");
+
+  // NOTE: The checks in the function are incomplete and currently miss illegal
+  // cases! The current implementation is a starting point and the
+  // implementation should be made stricter over time.
+  if (auto *C = dyn_cast<Constant>(B)) {
+    // Do not allow replacing a pointer with a constant pointer, unless it is
+    // either null or at least one byte is dereferenceable.
+    APInt OneByte(DL.getPointerTypeSizeInBits(A->getType()), 1);
+    return C->isNullValue() ||
+           isDereferenceableAndAlignedPointer(B, Align(1), OneByte, DL, CtxI);
+  }
+
+  return true;
+}

diff  --git a/llvm/unittests/Analysis/LoadsTest.cpp b/llvm/unittests/Analysis/LoadsTest.cpp
index 64758ebd39d1..0ee1a5fa08a3 100644
--- a/llvm/unittests/Analysis/LoadsTest.cpp
+++ b/llvm/unittests/Analysis/LoadsTest.cpp
@@ -59,3 +59,42 @@ define i32 @f() {
   ASSERT_TRUE(CI);
   ASSERT_TRUE(CI->equalsInt(42));
 }
+
+TEST(LoadsTest, CanReplacePointersIfEqual) {
+  LLVMContext C;
+  std::unique_ptr<Module> M = parseIR(C,
+                                      R"IR(
+ at y = common global [1 x i32] zeroinitializer, align 4
+ at x = common global [1 x i32] zeroinitializer, align 4
+
+declare void @use(i32*)
+
+define void @f(i32* %p) {
+  call void @use(i32* getelementptr inbounds ([1 x i32], [1 x i32]* @y, i64 0, i64 0))
+  call void @use(i32* getelementptr inbounds (i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @x, i64 0, i64 0), i64 1))
+  ret void
+}
+)IR");
+  const auto &DL = M->getDataLayout();
+  auto *GV = M->getNamedValue("f");
+  ASSERT_TRUE(GV);
+  auto *F = dyn_cast<Function>(GV);
+  ASSERT_TRUE(F);
+
+  // NOTE: the implementation of canReplacePointersIfEqual is incomplete.
+  // Currently the only the cases it returns false for are really sound and
+  // returning true means unknown.
+  Value *P = &*F->arg_begin();
+  auto InstIter = F->front().begin();
+  Value *ConstDerefPtr = *cast<CallInst>(&*InstIter)->arg_begin();
+  // ConstDerefPtr is a constant pointer that is provably de-referenceable. We
+  // can replace an arbitrary pointer with it.
+  EXPECT_TRUE(canReplacePointersIfEqual(P, ConstDerefPtr, DL, nullptr));
+
+  ++InstIter;
+  Value *ConstUnDerefPtr = *cast<CallInst>(&*InstIter)->arg_begin();
+  // ConstUndDerefPtr is a constant pointer that is provably not
+  // de-referenceable. We cannot replace an arbitrary pointer with it.
+  EXPECT_FALSE(
+      canReplacePointersIfEqual(ConstDerefPtr, ConstUnDerefPtr, DL, nullptr));
+}


        


More information about the llvm-commits mailing list