Transform a load from an undef/zero global into an undef/global even if we
authorChris Lattner <sabre@nondot.org>
Sat, 11 Aug 2007 18:48:48 +0000 (18:48 +0000)
committerChris Lattner <sabre@nondot.org>
Sat, 11 Aug 2007 18:48:48 +0000 (18:48 +0000)
have complex pointer manipulation going on.  This allows us to compile
stuff like this:

__m128i foo(__m128i x){
                static const unsigned int c_0[4] = { 0, 0, 0, 0 };
                __m128i v_Zero = _mm_loadu_si128((__m128i*)c_0);
                x  = _mm_unpacklo_epi8(x,  v_Zero);
                return x;
}

into:

_foo:
        xorps   %xmm1, %xmm1
        punpcklbw       %xmm1, %xmm0
        ret

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@41022 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Scalar/InstructionCombining.cpp
test/Transforms/InstCombine/load2.ll [new file with mode: 0644]

index 7532643e6c9f3f0785c729f6d255aa0f0861d922..2fad0abb151ab5e002fc1572b410897a944f6ed2 100644 (file)
@@ -8782,6 +8782,28 @@ static bool isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom) {
   return false;
 }
 
+/// GetUnderlyingObject - Trace through a series of getelementptrs and bitcasts
+/// until we find the underlying object a pointer is referring to or something
+/// we don't understand.  Note that the returned pointer may be offset from the
+/// input, because we ignore GEP indices.
+static Value *GetUnderlyingObject(Value *Ptr) {
+  while (1) {
+    if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Ptr)) {
+      if (CE->getOpcode() == Instruction::BitCast ||
+          CE->getOpcode() == Instruction::GetElementPtr)
+        Ptr = CE->getOperand(0);
+      else
+        return Ptr;
+    } else if (BitCastInst *BCI = dyn_cast<BitCastInst>(Ptr)) {
+      Ptr = BCI->getOperand(0);
+    } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Ptr)) {
+      Ptr = GEP->getOperand(0);
+    } else {
+      return Ptr;
+    }
+  }
+}
+
 Instruction *InstCombiner::visitLoadInst(LoadInst &LI) {
   Value *Op = LI.getOperand(0);
 
@@ -8860,6 +8882,17 @@ Instruction *InstCombiner::visitLoadInst(LoadInst &LI) {
           return Res;
       }
   }
+    
+  // If this load comes from anywhere in a constant global, and if the global
+  // is all undef or zero, we know what it loads.
+  if (GlobalVariable *GV = dyn_cast<GlobalVariable>(GetUnderlyingObject(Op))) {
+    if (GV->isConstant() && GV->hasInitializer()) {
+      if (GV->getInitializer()->isNullValue())
+        return ReplaceInstUsesWith(LI, Constant::getNullValue(LI.getType()));
+      else if (isa<UndefValue>(GV->getInitializer()))
+        return ReplaceInstUsesWith(LI, UndefValue::get(LI.getType()));
+    }
+  }
 
   if (Op->hasOneUse()) {
     // Change select and PHI nodes to select values instead of addresses: this
diff --git a/test/Transforms/InstCombine/load2.ll b/test/Transforms/InstCombine/load2.ll
new file mode 100644 (file)
index 0000000..5c3cf33
--- /dev/null
@@ -0,0 +1,11 @@
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis | not grep load
+
+@GLOBAL = internal constant [4 x i32] zeroinitializer
+
+
+define <16 x i8> @foo(<2 x i64> %x) {
+entry:
+       %tmp = load <16 x i8> * bitcast ([4 x i32]* @GLOBAL to <16 x i8>*)
+       ret <16 x i8> %tmp
+}
+