[llvm] fee8f56 - [ConstraintElimination] Include index type scale.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 9 13:54:21 PDT 2022


Author: Florian Hahn
Date: 2022-10-09T21:53:30+01:00
New Revision: fee8f561bdc9317eee13b8f1866ca0dc778c1dc5

URL: https://github.com/llvm/llvm-project/commit/fee8f561bdc9317eee13b8f1866ca0dc778c1dc5
DIFF: https://github.com/llvm/llvm-project/commit/fee8f561bdc9317eee13b8f1866ca0dc778c1dc5.diff

LOG: [ConstraintElimination] Include index type scale.

The current decomposition for GEPs did not correctly handle cases where
GEPs access different source types. Adjust the constraints by including
the indexed type-size as coefficients.

Further generalization to allow GEPs with more than one index is a
needed general follow-up improvement.

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
    llvm/test/Transforms/ConstraintElimination/gep-arithmetic-different-types.ll
    llvm/test/Transforms/ConstraintElimination/geps-unsigned-predicates.ll
    llvm/test/Transforms/ConstraintElimination/large-constant-ints.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 868e1c7c5ef0..f66f7644403d 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -22,6 +22,7 @@
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Function.h"
+#include "llvm/IR/GetElementPtrTypeIterator.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/PatternMatch.h"
@@ -185,7 +186,7 @@ struct DecompEntry {
 // be decomposed, returns an empty vector.
 static SmallVector<DecompEntry, 4>
 decompose(Value *V, SmallVector<PreconditionTy, 4> &Preconditions,
-          bool IsSigned) {
+          bool IsSigned, const DataLayout &DL) {
 
   auto CanUseSExt = [](ConstantInt *CI) {
     const APInt &Val = CI->getValue();
@@ -211,61 +212,65 @@ decompose(Value *V, SmallVector<PreconditionTy, 4> &Preconditions,
     Value *Op0, *Op1;
     ConstantInt *CI;
 
+    auto GTI = gep_type_begin(GEP);
+    int64_t Scale = static_cast<int64_t>(
+        DL.getTypeAllocSize(GTI.getIndexedType()).getFixedSize());
+    int64_t MulRes;
     // Handle the (gep (gep ....), C) case by incrementing the constant
     // coefficient of the inner GEP, if C is a constant.
     auto *InnerGEP = dyn_cast<GetElementPtrInst>(GEP->getPointerOperand());
     if (InnerGEP && InnerGEP->getNumOperands() == 2 &&
         isa<ConstantInt>(GEP->getOperand(1))) {
       APInt Offset = cast<ConstantInt>(GEP->getOperand(1))->getValue();
-      auto Result = decompose(InnerGEP, Preconditions, IsSigned);
-      Result[0].Coefficient += Offset.getSExtValue();
-      if (Offset.isNegative()) {
-        // Add pre-condition ensuring the GEP is increasing monotonically and
-        // can be de-composed.
-        Preconditions.emplace_back(
-            CmpInst::ICMP_SGE, InnerGEP->getOperand(1),
-            ConstantInt::get(InnerGEP->getOperand(1)->getType(),
-                             -1 * Offset.getSExtValue()));
+      auto Result = decompose(InnerGEP, Preconditions, IsSigned, DL);
+      if (!MulOverflow(Scale, Offset.getSExtValue(), MulRes)) {
+        Result[0].Coefficient += MulRes;
+        if (Offset.isNegative()) {
+          // Add pre-condition ensuring the GEP is increasing monotonically and
+          // can be de-composed.
+          Preconditions.emplace_back(
+              CmpInst::ICMP_SGE, InnerGEP->getOperand(1),
+              ConstantInt::get(InnerGEP->getOperand(1)->getType(),
+                               -1 * Offset.getSExtValue()));
+        }
+        return Result;
       }
-      return Result;
     }
 
     // If the index is zero-extended, it is guaranteed to be positive.
     if (match(GEP->getOperand(GEP->getNumOperands() - 1),
               m_ZExt(m_Value(Op0)))) {
       if (match(Op0, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))) &&
-          CanUseSExt(CI))
-        return {{0, nullptr},
-                {1, GEP->getPointerOperand()},
-                {int64_t(std::pow(int64_t(2), CI->getSExtValue())), Op1}};
+          CanUseSExt(CI) &&
+          !MulOverflow(Scale, int64_t(std::pow(int64_t(2), CI->getSExtValue())),
+                       MulRes))
+        return {{0, nullptr}, {1, GEP->getPointerOperand()}, {MulRes, Op1}};
       if (match(Op0, m_NSWAdd(m_Value(Op1), m_ConstantInt(CI))) &&
-          CanUseSExt(CI))
-        return {{CI->getSExtValue(), nullptr},
-                {1, GEP->getPointerOperand()},
-                {1, Op1}};
-      return {{0, nullptr}, {1, GEP->getPointerOperand()}, {1, Op0, true}};
+          CanUseSExt(CI) && match(Op0, m_NUWAdd(m_Value(), m_Value())) &&
+          !MulOverflow(Scale, CI->getSExtValue(), MulRes))
+        return {{MulRes, nullptr}, {1, GEP->getPointerOperand()}, {Scale, Op1}};
+      return {{0, nullptr}, {1, GEP->getPointerOperand()}, {Scale, Op0, true}};
     }
 
     if (match(GEP->getOperand(GEP->getNumOperands() - 1), m_ConstantInt(CI)) &&
-        !CI->isNegative() && CanUseSExt(CI))
-      return {{CI->getSExtValue(), nullptr}, {1, GEP->getPointerOperand()}};
+        !CI->isNegative() && CanUseSExt(CI) &&
+        !MulOverflow(Scale, CI->getSExtValue(), MulRes))
+      return {{MulRes, nullptr}, {1, GEP->getPointerOperand()}};
 
     SmallVector<DecompEntry, 4> Result;
     if (match(GEP->getOperand(GEP->getNumOperands() - 1),
-              m_NUWShl(m_Value(Op0), m_ConstantInt(CI))) &&
-        CanUseSExt(CI))
-      Result = {{0, nullptr},
-                {1, GEP->getPointerOperand()},
-                {int(std::pow(int64_t(2), CI->getSExtValue())), Op0}};
+              m_NSWShl(m_Value(Op0), m_ConstantInt(CI))) &&
+        CanUseSExt(CI) &&
+        !MulOverflow(Scale, int64_t(std::pow(int64_t(2), CI->getSExtValue())),
+                     MulRes))
+      Result = {{0, nullptr}, {1, GEP->getPointerOperand()}, {MulRes, Op0}};
     else if (match(GEP->getOperand(GEP->getNumOperands() - 1),
                    m_NSWAdd(m_Value(Op0), m_ConstantInt(CI))) &&
-             CanUseSExt(CI))
-      Result = {{CI->getSExtValue(), nullptr},
-                {1, GEP->getPointerOperand()},
-                {1, Op0}};
+             CanUseSExt(CI) && !MulOverflow(Scale, CI->getSExtValue(), MulRes))
+      Result = {{MulRes, nullptr}, {1, GEP->getPointerOperand()}, {Scale, Op0}};
     else {
       Op0 = GEP->getOperand(GEP->getNumOperands() - 1);
-      Result = {{0, nullptr}, {1, GEP->getPointerOperand()}, {1, Op0}};
+      Result = {{0, nullptr}, {1, GEP->getPointerOperand()}, {Scale, Op0}};
     }
     // If Op0 is signed non-negative, the GEP is increasing monotonically and
     // can be de-composed.
@@ -281,11 +286,11 @@ decompose(Value *V, SmallVector<PreconditionTy, 4> &Preconditions,
     V = Op0;
   }
 
-  auto MergeResults = [&Preconditions, IsSigned](
-                          Value *A, Value *B,
-                          bool IsSignedB) -> SmallVector<DecompEntry, 4> {
-    auto ResA = decompose(A, Preconditions, IsSigned);
-    auto ResB = decompose(B, Preconditions, IsSignedB);
+  auto MergeResults = [&Preconditions, IsSigned,
+                       DL](Value *A, Value *B,
+                           bool IsSignedB) -> SmallVector<DecompEntry, 4> {
+    auto ResA = decompose(A, Preconditions, IsSigned, DL);
+    auto ResB = decompose(B, Preconditions, IsSignedB, DL);
     if (ResA.empty() || ResB.empty())
       return {};
     ResA[0].Coefficient += ResB[0].Coefficient;
@@ -355,9 +360,9 @@ ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
   bool IsSigned = CmpInst::isSigned(Pred);
   auto &Value2Index = getValue2Index(IsSigned);
   auto ADec = decompose(Op0->stripPointerCastsSameRepresentation(),
-                        Preconditions, IsSigned);
+                        Preconditions, IsSigned, DL);
   auto BDec = decompose(Op1->stripPointerCastsSameRepresentation(),
-                        Preconditions, IsSigned);
+                        Preconditions, IsSigned, DL);
   // Skip if decomposing either of the values failed.
   if (ADec.empty() || BDec.empty())
     return {};

diff  --git a/llvm/test/Transforms/ConstraintElimination/gep-arithmetic-
diff erent-types.ll b/llvm/test/Transforms/ConstraintElimination/gep-arithmetic-
diff erent-types.ll
index 86d223fa656b..dc7253b45487 100644
--- a/llvm/test/Transforms/ConstraintElimination/gep-arithmetic-
diff erent-types.ll
+++ b/llvm/test/Transforms/ConstraintElimination/gep-arithmetic-
diff erent-types.ll
@@ -12,7 +12,7 @@ define i1 @gep_constant_positive_index(ptr %A, ptr %upper) {
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult ptr [[ADD_I16_4]], [[UPPER]]
 ; CHECK-NEXT:    [[ADD_I16_2:%.*]] = getelementptr inbounds i16, ptr [[A]], i64 2
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult ptr [[ADD_I16_2]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_1]], true
 ; CHECK-NEXT:    ret i1 [[RES_1]]
 ;
   %add.i8.4 = getelementptr inbounds i8, ptr %A, i64 4
@@ -38,7 +38,7 @@ define i1 @gep_constant_positive_index_chained(ptr %A, ptr %upper) {
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult ptr [[ADD_I16_1]], [[UPPER]]
 ; CHECK-NEXT:    [[ADD_I16_2:%.*]] = getelementptr inbounds i16, ptr [[ADD_I8_1]], i64 2
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult ptr [[ADD_I16_2]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, [[C_1]]
 ; CHECK-NEXT:    ret i1 [[RES_1]]
 ;
   %add.i8.4 = getelementptr inbounds i8, ptr %A, i64 4
@@ -66,7 +66,7 @@ define i1 @gep_var_positive_index(ptr %A, ptr %upper, i8 %idx) {
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult ptr [[ADD_I32_IDX]], [[UPPER]]
 ; CHECK-NEXT:    [[ADD_I8_IDX:%.*]] = getelementptr inbounds i8, ptr [[A]], i8 [[IDX]]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult ptr [[ADD_I8_IDX]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_1]], true
 ; CHECK-NEXT:    ret i1 [[RES_1]]
 ;
   %idx.pos = icmp sge i8 %idx, 0
@@ -96,10 +96,10 @@ define i1 @gep_add_nsw_positive_index(ptr %A, ptr %upper, i8 %idx) {
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult ptr [[ADD_I32_IDX_1]], [[UPPER]]
 ; CHECK-NEXT:    [[ADD_I8_IDX_1:%.*]] = getelementptr inbounds i8, ptr [[A]], i8 [[IDX_1]]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult ptr [[ADD_I8_IDX_1]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_1]], true
 ; CHECK-NEXT:    [[ADD_I16_IDX_1:%.*]] = getelementptr inbounds i16, ptr [[A]], i8 [[IDX_1]]
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ult ptr [[ADD_I16_IDX_1]], [[UPPER]]
-; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], true
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_2]]
 ; CHECK-NEXT:    ret i1 [[RES_2]]
 ;
   %idx.pos = icmp sge i8 %idx, 0
@@ -136,7 +136,7 @@ define i1 @gep_shl_nsw_positive_index(ptr %A, ptr %upper, i8 %idx) {
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult ptr [[ADD_I32_IDX_1]], [[UPPER]]
 ; CHECK-NEXT:    [[ADD_I8_IDX_1:%.*]] = getelementptr inbounds i8, ptr [[A]], i8 [[IDX_1]]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult ptr [[ADD_I8_IDX_1]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_1]], [[T_1]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_1]], true
 ; CHECK-NEXT:    ret i1 [[RES_1]]
 ;
   %idx.pos = icmp sge i8 %idx, 0
@@ -168,10 +168,10 @@ define i1 @gep_zext_add_nuw_nsw_index(ptr %A, ptr %upper, i8 %idx) {
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult ptr [[ADD_I32_IDX_1]], [[UPPER]]
 ; CHECK-NEXT:    [[ADD_I8_IDX_1:%.*]] = getelementptr inbounds i8, ptr [[A]], i16 [[IDX_1_EXT]]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult ptr [[ADD_I8_IDX_1]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_1]], true
 ; CHECK-NEXT:    [[ADD_I16_IDX_1:%.*]] = getelementptr inbounds i16, ptr [[A]], i16 [[IDX_1_EXT]]
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ult ptr [[ADD_I16_IDX_1]], [[UPPER]]
-; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], true
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_2]]
 ; CHECK-NEXT:    ret i1 [[RES_2]]
 ;
   %idx.3 = add nuw nsw i8 %idx, 3
@@ -240,7 +240,7 @@ define i1 @gep_zext_add_nsw_index(ptr %A, ptr %upper, i8 %idx) {
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult ptr [[ADD_I32_IDX_1]], [[UPPER]]
 ; CHECK-NEXT:    [[ADD_I8_IDX_1:%.*]] = getelementptr inbounds i8, ptr [[A]], i16 [[IDX_1_EXT]]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult ptr [[ADD_I8_IDX_1]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_1]], [[T_1]]
 ; CHECK-NEXT:    ret i1 [[RES_1]]
 ;
   %idx.2 = add nsw i8 %idx, 2
@@ -270,7 +270,7 @@ define i1 @gep_zext_index(ptr %A, ptr %upper, i8 %idx.1, i8 %idx.2) {
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult ptr [[ADD_I32_IDX_1]], [[ADD_I8_IDX_2]]
 ; CHECK-NEXT:    [[ADD_I8_IDX_1:%.*]] = getelementptr inbounds i8, ptr [[A]], i16 [[IDX_1_EXT]]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult ptr [[ADD_I8_IDX_1]], [[ADD_I8_IDX_2]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_1]], true
 ; CHECK-NEXT:    ret i1 [[RES_1]]
 ;
   %c.0 = icmp ult i8 %idx.1, %idx.2
@@ -335,7 +335,7 @@ define i1 @gep_zext_shl_nuw_index(ptr %A, ptr %upper, i8 %idx) {
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult ptr [[ADD_I32_IDX_1]], [[UPPER]]
 ; CHECK-NEXT:    [[ADD_I8_IDX_1:%.*]] = getelementptr inbounds i8, ptr [[A]], i16 [[IDX_1_EXT]]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult ptr [[ADD_I8_IDX_1]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_1]], true
 ; CHECK-NEXT:    ret i1 [[RES_1]]
 ;
   %idx.pos = icmp sgt i8 %idx, 0
@@ -371,13 +371,13 @@ define i1 @gep_add_nsw_positive_index_struct(ptr %A, ptr %upper, i8 %idx) {
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult ptr [[ADD_I32_IDX_1]], [[UPPER]]
 ; CHECK-NEXT:    [[ADD_I8_IDX_1:%.*]] = getelementptr inbounds i8, ptr [[A]], i8 [[IDX_1]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[ADD_I8_IDX_1]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_1]], true
 ; CHECK-NEXT:    [[ADD_I16_IDX_1:%.*]] = getelementptr inbounds i16, ptr [[A]], i8 [[IDX_1]]
 ; CHECK-NEXT:    [[T_3:%.*]] = icmp ult ptr [[ADD_I16_IDX_1]], [[UPPER]]
 ; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], true
 ; CHECK-NEXT:    [[ADD_I64_IDX_1:%.*]] = getelementptr inbounds i64, ptr [[A]], i8 [[IDX_1]]
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult ptr [[ADD_I64_IDX_1]], [[UPPER]]
-; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], true
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], [[C_1]]
 ; CHECK-NEXT:    ret i1 [[RES_3]]
 ;
   %idx.pos = icmp sge i8 %idx, 0

diff  --git a/llvm/test/Transforms/ConstraintElimination/geps-unsigned-predicates.ll b/llvm/test/Transforms/ConstraintElimination/geps-unsigned-predicates.ll
index 1590d7cb6d78..51eb96c38c1c 100644
--- a/llvm/test/Transforms/ConstraintElimination/geps-unsigned-predicates.ll
+++ b/llvm/test/Transforms/ConstraintElimination/geps-unsigned-predicates.ll
@@ -510,7 +510,7 @@ define void @test.ult.gep.shl(ptr readonly %src, ptr readnone %max, i8 %idx) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[IDX:%.*]], 5
 ; CHECK-NEXT:    br i1 [[CMP]], label [[CHECK_MAX:%.*]], label [[TRAP]]
 ; CHECK:       check.max:
-; CHECK-NEXT:    [[IDX_SHL_1:%.*]] = shl nuw i8 [[IDX]], 1
+; CHECK-NEXT:    [[IDX_SHL_1:%.*]] = shl nuw nsw i8 [[IDX]], 1
 ; CHECK-NEXT:    [[ADD_PTR_SHL_1:%.*]] = getelementptr inbounds i32, ptr [[SRC]], i8 [[IDX_SHL_1]]
 ; CHECK-NEXT:    [[C_MAX_0:%.*]] = icmp ult ptr [[ADD_PTR_SHL_1]], [[MAX]]
 ; CHECK-NEXT:    call void @use(i1 true)
@@ -541,7 +541,7 @@ check.idx:
   br i1 %cmp, label %check.max, label %trap
 
 check.max:
-  %idx.shl.1 = shl nuw i8 %idx, 1
+  %idx.shl.1 = shl nsw nuw i8 %idx, 1
   %add.ptr.shl.1 = getelementptr inbounds i32, ptr %src, i8 %idx.shl.1
   %c.max.0 = icmp ult ptr %add.ptr.shl.1, %max
   call void @use(i1 %c.max.0)

diff  --git a/llvm/test/Transforms/ConstraintElimination/large-constant-ints.ll b/llvm/test/Transforms/ConstraintElimination/large-constant-ints.ll
index be04ded7535b..a487376d639a 100644
--- a/llvm/test/Transforms/ConstraintElimination/large-constant-ints.ll
+++ b/llvm/test/Transforms/ConstraintElimination/large-constant-ints.ll
@@ -303,3 +303,17 @@ define i1 @add_minus_one_decomp_recursive() {
   %cmp = icmp uge i64 %add, 10
   ret i1 %cmp
 }
+
+define i1 @gep_decomp_large_index(ptr %a) {
+entry:
+  %gep.1 = getelementptr inbounds i64, ptr %a, i64 2147483646
+  %gep.2 = getelementptr inbounds i64, ptr %a, i64 2147483647
+  %ne = icmp ne ptr %gep.1, %gep.2
+  call void @llvm.assume(i1 %ne)
+  %cmp.ule = icmp ule ptr %gep.1, %gep.2
+  %cmp.uge = icmp uge ptr %gep.1, %gep.2
+  %res = xor i1 true, false
+  ret i1 %res
+}
+
+declare void @llvm.assume(i1)


        


More information about the llvm-commits mailing list