[PATCH] D43457: [Evaluator] Improve evaluation of load/store

Eugene Leviant via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 19 05:16:08 PST 2018


evgeny777 created this revision.
evgeny777 added reviewers: tejohnson, espindola, pcc.
Herald added a subscriber: mehdi_amini.
evgeny777 retitled this revision from "[Evaluator] Improve evaluation of bitcast" to "[Evaluator] Improve evaluation of load/store".

When storing pointers in struct/class constructor `clang` often generates IR like this:

  define internal void @_GLOBAL__sub_I_main.cpp()  {
    %1 = load i64, i64* bitcast (%struct.A** @gA to i64*), align 8
    store i64 %1, i64* bitcast (%struct.S* @s to i64*), align 8
    ret void
  }

which corresponds to following C++ code:

  extern A *gA;
  struct S {
    A* _a;
  } SObj(gA);

With https://reviews.llvm.org/D43077 it is now possible to import variables from different TU when using ThinLTO,
so it would be nice to optimize such static ctors out.


https://reviews.llvm.org/D43457

Files:
  lib/Transforms/Utils/Evaluator.cpp
  test/Transforms/GlobalOpt/evaluate-bitcast.ll


Index: test/Transforms/GlobalOpt/evaluate-bitcast.ll
===================================================================
--- test/Transforms/GlobalOpt/evaluate-bitcast.ll
+++ test/Transforms/GlobalOpt/evaluate-bitcast.ll
@@ -0,0 +1,28 @@
+; RUN: opt -globalopt -instcombine %s -S -o - | FileCheck %s
+
+; Static constructor should have been optimized out
+; CHECK:       i32 @main
+; CHECK-NEXT:     ret i32 69905
+; CHECK-NOT:   _GLOBAL__sub_I_main.cpp
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+%struct.S = type { %struct.A* }
+%struct.A = type { i64, i64 }
+
+ at s = internal local_unnamed_addr global %struct.S zeroinitializer, align 8
+ at llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_main.cpp, i8* null }]
+ at gA = available_externally dso_local local_unnamed_addr global %struct.A* inttoptr (i64 69905 to %struct.A*), align 8
+
+define dso_local i32 @main() local_unnamed_addr {
+  %1 = load i64, i64* bitcast (%struct.S* @s to i64*), align 8
+  %2 = trunc i64 %1 to i32
+  ret i32 %2
+}
+
+define internal void @_GLOBAL__sub_I_main.cpp() section ".text.startup" {
+  %1 = load i64, i64* bitcast (%struct.A** @gA to i64*), align 8
+  store i64 %1, i64* bitcast (%struct.S* @s to i64*), align 8
+  ret void
+}
Index: lib/Transforms/Utils/Evaluator.cpp
===================================================================
--- lib/Transforms/Utils/Evaluator.cpp
+++ lib/Transforms/Utils/Evaluator.cpp
@@ -190,13 +190,24 @@
   }
 
   // Handle a constantexpr getelementptr.
-  if (ConstantExpr *CE = dyn_cast<ConstantExpr>(P))
+  if (ConstantExpr *CE = dyn_cast<ConstantExpr>(P)) {
     if (CE->getOpcode() == Instruction::GetElementPtr &&
         isa<GlobalVariable>(CE->getOperand(0))) {
       GlobalVariable *GV = cast<GlobalVariable>(CE->getOperand(0));
       if (GV->hasDefinitiveInitializer())
         return ConstantFoldLoadThroughGEPConstantExpr(GV->getInitializer(), CE);
+    } else if (CE->getOpcode() == Instruction::BitCast) {
+      GlobalVariable *GV = dyn_cast<GlobalVariable>(CE->getOperand(0));
+      if (GV && GV->hasDefinitiveInitializer()) {
+        // We should always load from a pointer
+        assert(P->getType()->isPointerTy());
+        auto *ResTy = P->getType()->getContainedType(0);
+        auto *I = GV->getInitializer();
+        if (I->getType()->isPointerTy() && ResTy->isIntegerTy())
+          return ConstantExpr::getPtrToInt(I, ResTy);
+      }
     }
+  }
 
   return nullptr;  // don't know how to evaluate.
 }
@@ -249,10 +260,15 @@
 
           Type *NewTy = cast<PointerType>(Ptr->getType())->getElementType();
 
+          auto TypeConversionSafe = [](Type *VTy, Type *Ty) {
+            return (VTy->isIntegerTy() && Ty->isPointerTy()) ||
+                   VTy->canLosslesslyBitCastTo(Ty);
+          };
           // In order to push the bitcast onto the stored value, a bitcast
           // from NewTy to Val's type must be legal.  If it's not, we can try
           // introspecting NewTy to find a legal conversion.
-          while (!Val->getType()->canLosslesslyBitCastTo(NewTy)) {
+          auto *VTy = Val->getType();
+          while (!TypeConversionSafe(VTy, NewTy)) {
             // If NewTy is a struct, we can convert the pointer to the struct
             // into a pointer to its first member.
             // FIXME: This could be extended to support arrays as well.
@@ -277,8 +293,9 @@
           }
 
           // If we found compatible types, go ahead and push the bitcast
-          // onto the stored value.
-          Val = ConstantExpr::getBitCast(Val, NewTy);
+          // onto the stored value or convert it from integer to pointer.
+          Val = VTy->isIntegerTy() ? ConstantExpr::getIntToPtr(Val, NewTy)
+                                   : ConstantExpr::getBitCast(Val, NewTy);
 
           DEBUG(dbgs() << "Evaluated bitcast: " << *Val << "\n");
         }


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D43457.134896.patch
Type: text/x-patch
Size: 3988 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20180219/3e4c8243/attachment.bin>


More information about the llvm-commits mailing list