InstSimplify: Simplify trivial pointer expressions like b + (e - b)
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 26 Aug 2014 05:55:16 +0000 (05:55 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 26 Aug 2014 05:55:16 +0000 (05:55 +0000)
consider:
long long *f(long long *b, long long *e) {
  return b + (e - b);
}

we would lower this to something like:
define i64* @f(i64* %b, i64* %e) {
  %1 = ptrtoint i64* %e to i64
  %2 = ptrtoint i64* %b to i64
  %3 = sub i64 %1, %2
  %4 = ashr exact i64 %3, 3
  %5 = getelementptr inbounds i64* %b, i64 %4
  ret i64* %5
}

This should fold away to just 'e'.

N.B.  This adds m_SpecificInt as a convenient way to match against a
particular 64-bit integer when using LLVM's match interface.

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

include/llvm/IR/PatternMatch.h
lib/Analysis/InstructionSimplify.cpp
test/Transforms/InstSimplify/gep.ll [new file with mode: 0644]

index 2efb2948947374248a11dd3dbd4b523ec64bfd1a..530ad824b3732693661ed73ab94c4f6fe30c8a24 100644 (file)
@@ -362,6 +362,29 @@ struct bind_const_intval_ty {
   }
 };
 
+/// Match a specified integer value or vector of all elements of that value.
+struct specific_intval {
+  uint64_t Val;
+  specific_intval(uint64_t V) : Val(V) {}
+
+  template<typename ITy>
+  bool match(ITy *V) {
+    ConstantInt *CI = dyn_cast<ConstantInt>(V);
+    if (!CI && V->getType()->isVectorTy())
+      if (const auto *C = dyn_cast<Constant>(V))
+        CI = dyn_cast_or_null<ConstantInt>(C->getSplatValue());
+
+    if (CI && CI->getBitWidth() <= 64)
+      return CI->getZExtValue() == Val;
+
+    return false;
+  }
+};
+
+/// Match a specific integer value or vector with all elements equal to the
+/// value.
+inline specific_intval m_SpecificInt(uint64_t V) { return specific_intval(V); }
+
 /// m_ConstantInt - Match a ConstantInt and bind to its value.  This does not
 /// match ConstantInts wider than 64-bits.
 inline bind_const_intval_ty m_ConstantInt(uint64_t &V) { return V; }
index 459fc92bce1a856a2d621b6aedc24c76c18c2d1a..c9c9eede435ddbe599bd66ca3598f5b2cd672a16 100644 (file)
@@ -2783,6 +2783,7 @@ Value *llvm::SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
 static Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const Query &Q, unsigned) {
   // The type of the GEP pointer operand.
   PointerType *PtrTy = cast<PointerType>(Ops[0]->getType()->getScalarType());
+  unsigned AS = PtrTy->getAddressSpace();
 
   // getelementptr P -> P.
   if (Ops.size() == 1)
@@ -2791,7 +2792,7 @@ static Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const Query &Q, unsigned) {
   if (isa<UndefValue>(Ops[0])) {
     // Compute the (pointer) type returned by the GEP instruction.
     Type *LastType = GetElementPtrInst::getIndexedType(PtrTy, Ops.slice(1));
-    Type *GEPTy = PointerType::get(LastType, PtrTy->getAddressSpace());
+    Type *GEPTy = PointerType::get(LastType, AS);
     if (VectorType *VT = dyn_cast<VectorType>(Ops[0]->getType()))
       GEPTy = VectorType::get(GEPTy, VT->getNumElements());
     return UndefValue::get(GEPTy);
@@ -2801,11 +2802,41 @@ static Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const Query &Q, unsigned) {
     // getelementptr P, 0 -> P.
     if (match(Ops[1], m_Zero()))
       return Ops[0];
-    // getelementptr P, N -> P if P points to a type of zero size.
-    if (Q.DL) {
-      Type *Ty = PtrTy->getElementType();
-      if (Ty->isSized() && Q.DL->getTypeAllocSize(Ty) == 0)
+
+    Type *Ty = PtrTy->getElementType();
+    if (Q.DL && Ty->isSized()) {
+      Value *P;
+      uint64_t C;
+      uint64_t TyAllocSize = Q.DL->getTypeAllocSize(Ty);
+      // getelementptr P, N -> P if P points to a type of zero size.
+      if (TyAllocSize == 0)
         return Ops[0];
+
+      // The following transforms are only safe if the ptrtoint cast
+      // doesn't truncate the pointers.
+      if (Ops[1]->getType()->getScalarSizeInBits() ==
+          Q.DL->getPointerSizeInBits(AS)) {
+        // getelementptr P, (sub Q, P) -> Q if P points to a type of size 1.
+        if (TyAllocSize == 1 &&
+            match(Ops[1], m_Sub(m_PtrToInt(m_Value(P)),
+                                m_PtrToInt(m_Specific(Ops[0])))))
+          return P;
+
+        // getelementptr P, (ashr (sub Q, P), C) -> Q
+        // if P points to a type of size 1 << C.
+        if (match(Ops[1], m_AShr(m_Sub(m_PtrToInt(m_Value(P)),
+                                       m_PtrToInt(m_Specific(Ops[0]))),
+                                 m_ConstantInt(C))) &&
+            TyAllocSize == 1ULL << C)
+          return P;
+
+        // getelementptr P, (sdiv (sub Q, P), C) -> Q
+        // if P points to a type of size C.
+        if (match(Ops[1], m_SDiv(m_Sub(m_PtrToInt(m_Value(P)),
+                                       m_PtrToInt(m_Specific(Ops[0]))),
+                                 m_SpecificInt(TyAllocSize))))
+          return P;
+      }
     }
   }
 
diff --git a/test/Transforms/InstSimplify/gep.ll b/test/Transforms/InstSimplify/gep.ll
new file mode 100644 (file)
index 0000000..4bc3975
--- /dev/null
@@ -0,0 +1,37 @@
+; RUN: opt -S -instsimplify < %s | FileCheck %s
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+
+%struct.A = type { [7 x i8] }
+
+define %struct.A* @test1(%struct.A* %b, %struct.A* %e) {
+  %e_ptr = ptrtoint %struct.A* %e to i64
+  %b_ptr = ptrtoint %struct.A* %b to i64
+  %sub = sub i64 %e_ptr, %b_ptr
+  %sdiv = sdiv exact i64 %sub, 7
+  %gep = getelementptr inbounds %struct.A* %b, i64 %sdiv
+  ret %struct.A* %gep
+; CHECK-LABEL: @test1
+; CHECK-NEXT: ret %struct.A* %e
+}
+
+define i8* @test2(i8* %b, i8* %e) {
+  %e_ptr = ptrtoint i8* %e to i64
+  %b_ptr = ptrtoint i8* %b to i64
+  %sub = sub i64 %e_ptr, %b_ptr
+  %gep = getelementptr inbounds i8* %b, i64 %sub
+  ret i8* %gep
+; CHECK-LABEL: @test2
+; CHECK-NEXT: ret i8* %e
+}
+
+define i64* @test3(i64* %b, i64* %e) {
+  %e_ptr = ptrtoint i64* %e to i64
+  %b_ptr = ptrtoint i64* %b to i64
+  %sub = sub i64 %e_ptr, %b_ptr
+  %ashr = ashr exact i64 %sub, 3
+  %gep = getelementptr inbounds i64* %b, i64 %ashr
+  ret i64* %gep
+; CHECK-LABEL: @test3
+; CHECK-NEXT: ret i64* %e
+}