[llvm] 8086f9d - [ConstFold] Simplify a load's GEP operand through local aliases

Arthur Eubanks via llvm-commits llvm-commits at lists.llvm.org
Thu May 27 16:04:42 PDT 2021


Author: Arthur Eubanks
Date: 2021-05-27T16:04:19-07:00
New Revision: 8086f9d87ee81aacf829bdad94744a75cf692ebc

URL: https://github.com/llvm/llvm-project/commit/8086f9d87ee81aacf829bdad94744a75cf692ebc
DIFF: https://github.com/llvm/llvm-project/commit/8086f9d87ee81aacf829bdad94744a75cf692ebc.diff

LOG: [ConstFold] Simplify a load's GEP operand through local aliases

MSVC-style RTTI produces loads through a GEP of a local alias which
itself is a GEP. Currently we aren't able to devirtualize any virtual
calls when MSVC RTTI is enabled.

This patch attempts to simplify a load's GEP operand by calling
SymbolicallyEvaluateGEP() with an option to look through local aliases.

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

Added: 
    llvm/test/Transforms/InstSimplify/ConstProp/gep-alias-gep-load.ll

Modified: 
    llvm/lib/Analysis/ConstantFolding.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 7d4fcdc456fec..989379d22c615 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -63,6 +63,11 @@
 using namespace llvm;
 
 namespace {
+Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
+                                  ArrayRef<Constant *> Ops,
+                                  const DataLayout &DL,
+                                  const TargetLibraryInfo *TLI,
+                                  bool ForLoadOperand);
 
 //===----------------------------------------------------------------------===//
 // Constant Folding internal helper functions
@@ -690,6 +695,33 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
                 GV->getInitializer(), CE, Ty, DL))
           return V;
       }
+    } else {
+      // Try to simplify GEP if the pointer operand wasn't a GlobalVariable.
+      // SymbolicallyEvaluateGEP() with `ForLoadOperand = true` can potentially
+      // simplify the GEP more than it normally would have been, but should only
+      // be used for const folding loads.
+      SmallVector<Constant *> Ops;
+      for (unsigned I = 0, E = CE->getNumOperands(); I != E; ++I)
+        Ops.push_back(cast<Constant>(CE->getOperand(I)));
+      if (auto *Simplified = dyn_cast_or_null<ConstantExpr>(
+              SymbolicallyEvaluateGEP(cast<GEPOperator>(CE), Ops, DL, nullptr,
+                                      /*ForLoadOperand*/ true))) {
+        // If the symbolically evaluated GEP is another GEP, we can only const
+        // fold it if the resulting pointer operand is a GlobalValue. Otherwise
+        // there is nothing else to simplify since the GEP is already in the
+        // most simplified form.
+        if (auto *SimplifiedGEP = dyn_cast<GEPOperator>(Simplified)) {
+          if (auto *GV = dyn_cast<GlobalVariable>(Simplified->getOperand(0))) {
+            if (GV->isConstant() && GV->hasDefinitiveInitializer()) {
+              if (Constant *V = ConstantFoldLoadThroughGEPConstantExpr(
+                      GV->getInitializer(), Simplified, Ty, DL))
+                return V;
+            }
+          }
+        } else {
+          return ConstantFoldLoadFromConstPtr(Simplified, Ty, DL);
+        }
+      }
     }
   }
 
@@ -835,10 +867,18 @@ Constant *CastGEPIndices(Type *SrcElemTy, ArrayRef<Constant *> Ops,
 }
 
 /// Strip the pointer casts, but preserve the address space information.
-Constant *StripPtrCastKeepAS(Constant *Ptr, Type *&ElemTy) {
+Constant *StripPtrCastKeepAS(Constant *Ptr, Type *&ElemTy,
+                             bool ForLoadOperand) {
   assert(Ptr->getType()->isPointerTy() && "Not a pointer type");
   auto *OldPtrTy = cast<PointerType>(Ptr->getType());
   Ptr = cast<Constant>(Ptr->stripPointerCasts());
+  if (ForLoadOperand) {
+    while (isa<GlobalAlias>(Ptr) && !cast<GlobalAlias>(Ptr)->isInterposable() &&
+           !cast<GlobalAlias>(Ptr)->getBaseObject()->isInterposable()) {
+      Ptr = cast<GlobalAlias>(Ptr)->getAliasee();
+    }
+  }
+
   auto *NewPtrTy = cast<PointerType>(Ptr->getType());
 
   ElemTy = NewPtrTy->getPointerElementType();
@@ -855,7 +895,8 @@ Constant *StripPtrCastKeepAS(Constant *Ptr, Type *&ElemTy) {
 Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
                                   ArrayRef<Constant *> Ops,
                                   const DataLayout &DL,
-                                  const TargetLibraryInfo *TLI) {
+                                  const TargetLibraryInfo *TLI,
+                                  bool ForLoadOperand) {
   const GEPOperator *InnermostGEP = GEP;
   bool InBounds = GEP->isInBounds();
 
@@ -903,7 +944,7 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
             DL.getIndexedOffsetInType(
                 SrcElemTy,
                 makeArrayRef((Value * const *)Ops.data() + 1, Ops.size() - 1)));
-  Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy);
+  Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy, ForLoadOperand);
 
   // If this is a GEP of a GEP, fold it all into a single GEP.
   while (auto *GEP = dyn_cast<GEPOperator>(Ptr)) {
@@ -925,7 +966,7 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
     Ptr = cast<Constant>(GEP->getOperand(0));
     SrcElemTy = GEP->getSourceElementType();
     Offset += APInt(BitWidth, DL.getIndexedOffsetInType(SrcElemTy, NestedOps));
-    Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy);
+    Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy, ForLoadOperand);
   }
 
   // If the base value for this address is a literal integer value, fold the
@@ -1062,7 +1103,8 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
     return ConstantFoldCastOperand(Opcode, Ops[0], DestTy, DL);
 
   if (auto *GEP = dyn_cast<GEPOperator>(InstOrCE)) {
-    if (Constant *C = SymbolicallyEvaluateGEP(GEP, Ops, DL, TLI))
+    if (Constant *C = SymbolicallyEvaluateGEP(GEP, Ops, DL, TLI,
+                                              /*ForLoadOperand*/ false))
       return C;
 
     return ConstantExpr::getGetElementPtr(GEP->getSourceElementType(), Ops[0],

diff  --git a/llvm/test/Transforms/InstSimplify/ConstProp/gep-alias-gep-load.ll b/llvm/test/Transforms/InstSimplify/ConstProp/gep-alias-gep-load.ll
new file mode 100644
index 0000000000000..703f242739e6d
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/gep-alias-gep-load.ll
@@ -0,0 +1,35 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=instsimplify -S < %s | FileCheck %s
+
+ at a1 = internal alias i32, getelementptr ({[3 x i32]}, {[3 x i32]}* @b, i32 0, i32 0, i32 1)
+ at a2 = weak alias i32, getelementptr ({[3 x i32]}, {[3 x i32]}* @b, i32 0, i32 0, i32 1)
+ at b = internal constant {[3 x i32]} {[3 x i32] [i32 2, i32 3, i32 4]}
+
+ at c = internal alias i32, getelementptr ({[3 x i32]}, {[3 x i32]}* @d, i32 0, i32 0, i32 1)
+ at d = weak constant {[3 x i32]} {[3 x i32] [i32 2, i32 3, i32 4]}
+
+define i32 @f() {
+; CHECK-LABEL: @f(
+; CHECK-NEXT:    ret i32 4
+;
+  %a = load i32, i32* getelementptr (i32, i32* @a1, i64 1)
+  ret i32 %a
+}
+
+define i32 @g() {
+; CHECK-LABEL: @g(
+; CHECK-NEXT:    [[A:%.*]] = load i32, i32* getelementptr (i32, i32* @a2, i64 1), align 4
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  %a = load i32, i32* getelementptr (i32, i32* @a2, i64 1)
+  ret i32 %a
+}
+
+define i32 @h() {
+; CHECK-LABEL: @h(
+; CHECK-NEXT:    [[A:%.*]] = load i32, i32* getelementptr (i32, i32* @c, i64 1), align 4
+; CHECK-NEXT:    ret i32 [[A]]
+;
+  %a = load i32, i32* getelementptr (i32, i32* @c, i64 1)
+  ret i32 %a
+}


        


More information about the llvm-commits mailing list