]> granicus.if.org Git - llvm/commitdiff
[ConstantFold] Don't incorrectly infer inbounds on array GEP
authorDavid Majnemer <david.majnemer@gmail.com>
Wed, 13 Jul 2016 03:24:41 +0000 (03:24 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Wed, 13 Jul 2016 03:24:41 +0000 (03:24 +0000)
The many levels of nesting inside the responsible code made it easy for
bugs to sneak in.  Flattening the logic makes it easier to see what's
going on.

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

lib/IR/ConstantFold.cpp
test/Assembler/getelementptr.ll

index 575a88894ddb853cd3904c90d812545fe6e289d7..c06a99c053636bdf07d107fd361f172e08cc6ce1 100644 (file)
@@ -2192,51 +2192,68 @@ static Constant *ConstantFoldGetElementPtrImpl(Type *PointeeTy, Constant *C,
   bool Unknown = !isa<ConstantInt>(Idxs[0]);
   for (unsigned i = 1, e = Idxs.size(); i != e;
        Prev = Ty, Ty = cast<CompositeType>(Ty)->getTypeAtIndex(Idxs[i]), ++i) {
-    if (ConstantInt *CI = dyn_cast<ConstantInt>(Idxs[i])) {
-      if (isa<ArrayType>(Ty) && CI->getSExtValue() > 0 &&
-          !isIndexInRangeOfSequentialType(cast<ArrayType>(Ty), CI)) {
-        if (isa<SequentialType>(Prev)) {
-          // It's out of range, but we can factor it into the prior
-          // dimension.
-          NewIdxs.resize(Idxs.size());
-          uint64_t NumElements = 0;
-          if (auto *ATy = dyn_cast<ArrayType>(Ty))
-            NumElements = ATy->getNumElements();
-          else
-            NumElements = cast<VectorType>(Ty)->getNumElements();
-
-          ConstantInt *Factor = ConstantInt::get(CI->getType(), NumElements);
-          NewIdxs[i] = ConstantExpr::getSRem(CI, Factor);
-
-          Constant *PrevIdx = cast<Constant>(Idxs[i - 1]);
-          Constant *Div = ConstantExpr::getSDiv(CI, Factor);
-
-          unsigned CommonExtendedWidth =
-              std::max(PrevIdx->getType()->getIntegerBitWidth(),
-                       Div->getType()->getIntegerBitWidth());
-          CommonExtendedWidth = std::max(CommonExtendedWidth, 64U);
-
-          // Before adding, extend both operands to i64 to avoid
-          // overflow trouble.
-          if (!PrevIdx->getType()->isIntegerTy(CommonExtendedWidth))
-            PrevIdx = ConstantExpr::getSExt(
-                PrevIdx,
-                Type::getIntNTy(Div->getContext(), CommonExtendedWidth));
-          if (!Div->getType()->isIntegerTy(CommonExtendedWidth))
-            Div = ConstantExpr::getSExt(
-                Div, Type::getIntNTy(Div->getContext(), CommonExtendedWidth));
-
-          NewIdxs[i - 1] = ConstantExpr::getAdd(PrevIdx, Div);
-        } else {
-          // It's out of range, but the prior dimension is a struct
-          // so we can't do anything about it.
-          Unknown = true;
-        }
-        }
-    } else {
+    auto *CI = dyn_cast<ConstantInt>(Idxs[i]);
+    if (!CI) {
       // We don't know if it's in range or not.
       Unknown = true;
+      continue;
+    }
+    if (isa<StructType>(Ty)) {
+      // The verify makes sure that GEPs into a struct are in range.
+      continue;
+    }
+    auto *STy = cast<SequentialType>(Ty);
+    if (isa<PointerType>(STy)) {
+      // We don't know if it's in range or not.
+      Unknown = true;
+      continue;
+    }
+    if (isa<VectorType>(STy)) {
+      // There can be awkward padding in after a non-power of two vector.
+      Unknown = true;
+      continue;
+    }
+    if (isIndexInRangeOfSequentialType(STy, CI))
+      // It's in range, skip to the next index.
+      continue;
+    if (!isa<SequentialType>(Prev)) {
+      // It's out of range, but the prior dimension is a struct
+      // so we can't do anything about it.
+      Unknown = true;
+      continue;
+    }
+    if (CI->getSExtValue() < 0) {
+      // It's out of range and negative, don't try to factor it.
+      Unknown = true;
+      continue;
     }
+    // It's out of range, but we can factor it into the prior
+    // dimension.
+    NewIdxs.resize(Idxs.size());
+    // Determine the number of elements in our sequential type.
+    uint64_t NumElements = STy->getArrayNumElements();
+
+    ConstantInt *Factor = ConstantInt::get(CI->getType(), NumElements);
+    NewIdxs[i] = ConstantExpr::getSRem(CI, Factor);
+
+    Constant *PrevIdx = cast<Constant>(Idxs[i - 1]);
+    Constant *Div = ConstantExpr::getSDiv(CI, Factor);
+
+    unsigned CommonExtendedWidth =
+        std::max(PrevIdx->getType()->getIntegerBitWidth(),
+                 Div->getType()->getIntegerBitWidth());
+    CommonExtendedWidth = std::max(CommonExtendedWidth, 64U);
+
+    // Before adding, extend both operands to i64 to avoid
+    // overflow trouble.
+    if (!PrevIdx->getType()->isIntegerTy(CommonExtendedWidth))
+      PrevIdx = ConstantExpr::getSExt(
+          PrevIdx, Type::getIntNTy(Div->getContext(), CommonExtendedWidth));
+    if (!Div->getType()->isIntegerTy(CommonExtendedWidth))
+      Div = ConstantExpr::getSExt(
+          Div, Type::getIntNTy(Div->getContext(), CommonExtendedWidth));
+
+    NewIdxs[i - 1] = ConstantExpr::getAdd(PrevIdx, Div);
   }
 
   // If we did any factoring, start over with the adjusted indices.
index 0a0fddfc4dda7353434ad04c18f7eec2ca3d44f1..824848d77b58ce2eeaa17fb5bdbb7d4514f6adc8 100644 (file)
@@ -46,3 +46,13 @@ define <2 x i8*> @test8(<2 x [2 x i8]*> %a) {
   %w = getelementptr  [2 x i8], <2 x  [2 x i8]*> %a, <2 x i32> <i32 0, i32 0>, <2 x i8> <i8 0, i8 1>
   ret <2 x i8*> %w
 }
+
+@array = internal global [16 x i32] [i32 -200, i32 -199, i32 -198, i32 -197, i32 -196, i32 -195, i32 -194, i32 -193, i32 -192, i32 -191, i32 -190, i32 -189, i32 -188, i32 -187, i32 -186, i32 -185], align 16
+
+; Verify that array GEP doesn't incorrectly infer inbounds.
+define i32* @test9() {
+entry:
+  ret i32* getelementptr ([16 x i32], [16 x i32]* @array, i64 0, i64 -13)
+; CHECK-LABEL: define i32* @test9(
+; CHECK: ret i32* getelementptr ([16 x i32], [16 x i32]* @array, i64 0, i64 -13)
+}