[llvm] [InstCombine] Fold icmp(constants[x]) when the range of x is given (PR #67093)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 29 01:19:07 PST 2023


================
@@ -281,40 +278,57 @@ Instruction *InstCombinerImpl::foldCmpLoadFromIndexedGlobal(
 
   // Now that we've scanned the entire array, emit our new comparison(s).  We
   // order the state machines in complexity of the generated code.
-  Value *Idx = GEP->getOperand(2);
-
-  // If the index is larger than the pointer offset size of the target, truncate
-  // the index down like the GEP would do implicitly.  We don't have to do this
-  // for an inbounds GEP because the index can't be out of range.
-  if (!GEP->isInBounds()) {
-    Type *PtrIdxTy = DL.getIndexType(GEP->getType());
-    unsigned OffsetSize = PtrIdxTy->getIntegerBitWidth();
-    if (Idx->getType()->getPrimitiveSizeInBits().getFixedValue() > OffsetSize)
-      Idx = Builder.CreateTrunc(Idx, PtrIdxTy);
-  }
 
-  // If inbounds keyword is not present, Idx * ElementSize can overflow.
-  // Let's assume that ElementSize is 2 and the wanted value is at offset 0.
+  // If inbounds keyword is not present, Idx * LongestStep can overflow.
+  // Let's assume that LongestStep is 2 and the wanted value is at offset 0.
   // Then, there are two possible values for Idx to match offset 0:
   // 0x00..00, 0x80..00.
   // Emitting 'icmp eq Idx, 0' isn't correct in this case because the
   // comparison is false if Idx was 0x80..00.
   // We need to erase the highest countTrailingZeros(ElementSize) bits of Idx.
-  unsigned ElementSize =
-      DL.getTypeAllocSize(Init->getType()->getArrayElementType());
   auto MaskIdx = [&](Value *Idx) {
-    if (!GEP->isInBounds() && llvm::countr_zero(ElementSize) != 0) {
+    if (!GEP->isInBounds() && OffsetStep.countr_zero() != 0) {
       Value *Mask = ConstantInt::get(Idx->getType(), -1);
-      Mask = Builder.CreateLShr(Mask, llvm::countr_zero(ElementSize));
+      Mask = Builder.CreateLShr(Mask, OffsetStep.countr_zero());
       Idx = Builder.CreateAnd(Idx, Mask);
     }
     return Idx;
   };
 
+  // Build the index expression lazily.
+  auto LazyGetIndex = [&](Value *CurIdx) {
+    if (CurIdx)
+      return CurIdx;
+
+    // Initial bias for index. For example, when we fold cmp(GV[x + 3], C) into
+    // idx < 3, we actually get x + 3 < 3
+    Value *Idx = ConstantInt::get(
+        PtrIdxTy, (ConstantOffset - BeginOffset).sdiv(OffsetStep));
+    uint64_t IdxBitWidth = Idx->getType()->getScalarSizeInBits();
+    for (auto [Var, Coefficient] : VariableOffsets) {
+      uint64_t VarBitWidth = Var->getType()->getScalarSizeInBits();
+      assert("GEP indices do not get canonicalized to the index type" &&
+             VarBitWidth == IdxBitWidth);
+
+      APInt MinCoeffi = Coefficient.udiv(OffsetStep);
+      Value *Mul =
+          Builder.CreateMul(Var, ConstantInt::get(Idx->getType(), MinCoeffi));
+      Idx = Builder.CreateAdd(Idx, Mul);
+    }
+
+    // If the index is larger than the pointer offset size of the target,
+    // truncate the index down like the GEP would do implicitly.  We don't have
+    // to do this for an inbounds GEP because the index can't be out of range.
+    if (!GEP->isInBounds() && IdxBitWidth > IndexSize)
----------------
dtcxzyw wrote:

As we canonicalize the index's type of GEPs, I think we can skip the transform when `IdxBitWidth != IndexSize`.
 

https://github.com/llvm/llvm-project/pull/67093


More information about the llvm-commits mailing list