[llvm] 572d5d3 - [ConstraintElim] Add support for GEPs with multiple indices.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 13 13:09:05 PDT 2022


Author: Florian Hahn
Date: 2022-10-13T21:08:33+01:00
New Revision: 572d5d374c98e29214d4a49a03cfc5d33cb15744

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

LOG: [ConstraintElim] Add support for GEPs with multiple indices.

Lift restriction on GEPs with a single index by iterating over all
indices and joining the {Coefficient, Variable} entries for all indices
together.

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
    llvm/test/Transforms/ConstraintElimination/geps-pointers-to-arrays.ll
    llvm/test/Transforms/ConstraintElimination/geps-pointers-to-structs.ll
    llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index d02a9868a6e9..89d22a403a20 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -207,13 +207,9 @@ decomposeGEP(GetElementPtrInst &GEP,
   if (DL.getIndexSizeInBits(AS) > 64)
     return {};
 
-  auto GTI = gep_type_begin(GEP);
-  if (GEP.getNumOperands() != 2 || !GEP.isInBounds() ||
-      isa<ScalableVectorType>(GTI.getIndexedType()))
+  if (!GEP.isInBounds())
     return {{0, nullptr}, {1, &GEP}};
 
-  int64_t Scale = static_cast<int64_t>(
-      DL.getTypeAllocSize(GTI.getIndexedType()).getFixedSize());
   // 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());
@@ -221,6 +217,14 @@ decomposeGEP(GetElementPtrInst &GEP,
       isa<ConstantInt>(GEP.getOperand(1))) {
     APInt Offset = cast<ConstantInt>(GEP.getOperand(1))->getValue();
     auto Result = decompose(InnerGEP, Preconditions, IsSigned, DL);
+
+    auto GTI = gep_type_begin(GEP);
+    // Bail out for scalable vectors for now.
+    if (isa<ScalableVectorType>(GTI.getIndexedType()))
+      return {};
+    int64_t Scale = static_cast<int64_t>(
+        DL.getTypeAllocSize(GTI.getIndexedType()).getFixedSize());
+
     Result[0].Coefficient += multiplyWithOverflow(Scale, Offset.getSExtValue());
     if (Offset.isNegative()) {
       // Add pre-condition ensuring the GEP is increasing monotonically and
@@ -233,53 +237,84 @@ decomposeGEP(GetElementPtrInst &GEP,
     return Result;
   }
 
-  Value *Op0, *Op1;
-  ConstantInt *CI;
-  // 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()},
-              {multiplyWithOverflow(
-                   Scale, int64_t(std::pow(int64_t(2), CI->getSExtValue()))),
-               Op1}};
-    if (match(Op0, m_NSWAdd(m_Value(Op1), m_ConstantInt(CI))) &&
-        canUseSExt(CI) && match(Op0, m_NUWAdd(m_Value(), m_Value())))
-      return {{multiplyWithOverflow(Scale, CI->getSExtValue()), nullptr},
-              {1, GEP.getPointerOperand()},
-              {Scale, Op1}};
-
-    return {{0, nullptr}, {1, GEP.getPointerOperand()}, {Scale, Op0, true}};
-  }
+  SmallVector<DecompEntry, 4> Result = {{0, nullptr},
+                                        {1, GEP.getPointerOperand()}};
+  gep_type_iterator GTI = gep_type_begin(GEP);
+  for (User::const_op_iterator I = GEP.op_begin() + 1, E = GEP.op_end(); I != E;
+       ++I, ++GTI) {
+    Value *Index = *I;
+
+    // Bail out for scalable vectors for now.
+    if (isa<ScalableVectorType>(GTI.getIndexedType()))
+      return {};
+
+    // Struct indices must be constants (and reference an existing field). Add
+    // them to the constant factor.
+    if (StructType *STy = GTI.getStructTypeOrNull()) {
+      // For a struct, add the member offset.
+      unsigned FieldNo = cast<ConstantInt>(Index)->getZExtValue();
+      if (FieldNo == 0)
+        continue;
 
-  if (match(GEP.getOperand(GEP.getNumOperands() - 1), m_ConstantInt(CI)) &&
-      !CI->isNegative() && canUseSExt(CI))
-    return {{multiplyWithOverflow(Scale, CI->getSExtValue()), nullptr},
-            {1, GEP.getPointerOperand()}};
-
-  SmallVector<DecompEntry, 4> Result;
-  if (match(GEP.getOperand(GEP.getNumOperands() - 1),
-            m_NSWShl(m_Value(Op0), m_ConstantInt(CI))) &&
-      canUseSExt(CI))
-    Result = {{0, nullptr},
-              {1, GEP.getPointerOperand()},
-              {multiplyWithOverflow(
-                   Scale, int64_t(std::pow(int64_t(2), CI->getSExtValue()))),
-               Op0}};
-  else if (match(GEP.getOperand(GEP.getNumOperands() - 1),
-                 m_NSWAdd(m_Value(Op0), m_ConstantInt(CI))) &&
-           canUseSExt(CI))
-    Result = {{multiplyWithOverflow(Scale, CI->getSExtValue()), nullptr},
-              {1, GEP.getPointerOperand()},
-              {Scale, Op0}};
-  else {
-    Op0 = GEP.getOperand(GEP.getNumOperands() - 1);
-    Result = {{0, nullptr}, {1, GEP.getPointerOperand()}, {Scale, Op0}};
+      // Add offset to constant factor.
+      Result[0].Coefficient +=
+          DL.getStructLayout(STy)->getElementOffset(FieldNo);
+      continue;
+    }
+
+    // For an array/pointer, add the element offset, explicitly scaled.
+    unsigned Scale = DL.getTypeAllocSize(GTI.getIndexedType()).getFixedSize();
+
+    Value *Op0, *Op1;
+    ConstantInt *CI;
+    // If the index is zero-extended, it is guaranteed to be positive.
+    if (match(Index, m_ZExt(m_Value(Op0)))) {
+      if (match(Op0, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))) &&
+          canUseSExt(CI)) {
+        Result.emplace_back(
+            multiplyWithOverflow(
+                Scale, int64_t(std::pow(int64_t(2), CI->getSExtValue()))),
+            Op1);
+        continue;
+      }
+
+      if (match(Op0, m_NSWAdd(m_Value(Op1), m_ConstantInt(CI))) &&
+          canUseSExt(CI) && match(Op0, m_NUWAdd(m_Value(), m_Value()))) {
+        Result[0].Coefficient +=
+            multiplyWithOverflow(Scale, CI->getSExtValue());
+        Result.emplace_back(Scale, Op1);
+        continue;
+      }
+
+      Result.emplace_back(Scale, Op0, true);
+      continue;
+    }
+
+    if (match(Index, m_ConstantInt(CI)) && !CI->isNegative() &&
+        canUseSExt(CI)) {
+      Result[0].Coefficient += multiplyWithOverflow(Scale, CI->getSExtValue());
+      continue;
+    }
+
+    if (match(Index, m_NSWShl(m_Value(Op0), m_ConstantInt(CI))) &&
+        canUseSExt(CI)) {
+      Result.emplace_back(
+          multiplyWithOverflow(
+              Scale, int64_t(std::pow(int64_t(2), CI->getSExtValue()))),
+          Op0);
+    } else if (match(Index, m_NSWAdd(m_Value(Op0), m_ConstantInt(CI))) &&
+               canUseSExt(CI)) {
+      Result[0].Coefficient += multiplyWithOverflow(Scale, CI->getSExtValue());
+      Result.emplace_back(Scale, Op0);
+    } else {
+      Op0 = Index;
+      Result.emplace_back(Scale, Op0);
+    }
+    // If Op0 is signed non-negative, the GEP is increasing monotonically and
+    // can be de-composed.
+    Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0,
+                               ConstantInt::get(Op0->getType(), 0));
   }
-  // If Op0 is signed non-negative, the GEP is increasing monotonically and
-  // can be de-composed.
-  Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0,
-                             ConstantInt::get(Op0->getType(), 0));
   return Result;
 }
 

diff  --git a/llvm/test/Transforms/ConstraintElimination/geps-pointers-to-arrays.ll b/llvm/test/Transforms/ConstraintElimination/geps-pointers-to-arrays.ll
index 3f56736e3b95..db8140167ed9 100644
--- a/llvm/test/Transforms/ConstraintElimination/geps-pointers-to-arrays.ll
+++ b/llvm/test/Transforms/ConstraintElimination/geps-pointers-to-arrays.ll
@@ -10,7 +10,7 @@ define void @pointer.to.array.test.ult.true.due.to.first.dimension(ptr %start, p
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[START_0:%.*]] = getelementptr inbounds [10 x i8], ptr [[START]], i64 5, i64 0
 ; CHECK-NEXT:    [[C_0:%.*]] = icmp ult ptr [[START_0]], [[HIGH]]
-; CHECK-NEXT:    call void @use(i1 [[C_0]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.end:
 ; CHECK-NEXT:    ret void
@@ -68,7 +68,7 @@ define void @pointer.to.array.test.ult.true.due.to.second.dimension(ptr %start,
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[START_0:%.*]] = getelementptr inbounds [10 x i8], ptr [[START]], i64 5, i64 0
 ; CHECK-NEXT:    [[C_0:%.*]] = icmp ult ptr [[START_0]], [[HIGH]]
-; CHECK-NEXT:    call void @use(i1 [[C_0]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.end:
 ; CHECK-NEXT:    ret void

diff  --git a/llvm/test/Transforms/ConstraintElimination/geps-pointers-to-structs.ll b/llvm/test/Transforms/ConstraintElimination/geps-pointers-to-structs.ll
index bb0ef5293a3d..305ff8a24fd0 100644
--- a/llvm/test/Transforms/ConstraintElimination/geps-pointers-to-structs.ll
+++ b/llvm/test/Transforms/ConstraintElimination/geps-pointers-to-structs.ll
@@ -15,7 +15,7 @@ define i1 @test.ult.true.due.to.first.dimension(ptr %start, ptr %high) {
 ; CHECK-NEXT:    [[START_0:%.*]] = getelementptr inbounds [[STRUCT_1]], ptr [[START]], i64 5, i32 0
 ; CHECK-NEXT:    [[START_0_CAST:%.*]] = bitcast ptr [[START_0]] to ptr
 ; CHECK-NEXT:    [[C_0:%.*]] = icmp ult ptr [[START_0_CAST]], [[HIGH]]
-; CHECK-NEXT:    ret i1 [[C_0]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       if.end:
 ; CHECK-NEXT:    ret i1 true
 ;
@@ -49,7 +49,7 @@ define i1 @test.ult.true.due.to.first.dimension.var.index.0(ptr %start, ptr %hig
 ; CHECK-NEXT:    [[START_0:%.*]] = getelementptr inbounds [[STRUCT_1]], ptr [[START]], i64 [[IDX_EXT]], i32 0
 ; CHECK-NEXT:    [[START_0_CAST:%.*]] = bitcast ptr [[START_0]] to ptr
 ; CHECK-NEXT:    [[C_0:%.*]] = icmp ult ptr [[START_0_CAST]], [[HIGH]]
-; CHECK-NEXT:    ret i1 [[C_0]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       if.end:
 ; CHECK-NEXT:    ret i1 true
 ;
@@ -86,7 +86,7 @@ define i1 @test.ult.true.due.to.first.dimension.var.index.1(ptr %start, ptr %hig
 ; CHECK-NEXT:    [[START_0:%.*]] = getelementptr inbounds [[STRUCT_1]], ptr [[START]], i64 [[IDX_EXT]], i32 1
 ; CHECK-NEXT:    [[START_0_CAST:%.*]] = bitcast ptr [[START_0]] to ptr
 ; CHECK-NEXT:    [[C_0:%.*]] = icmp ult ptr [[START_0_CAST]], [[HIGH]]
-; CHECK-NEXT:    ret i1 [[C_0]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       if.end:
 ; CHECK-NEXT:    ret i1 true
 ;
@@ -122,7 +122,7 @@ define i1 @test.ult.true.due.to.first.dimension.var.index.2(ptr %start, ptr %hig
 ; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
 ; CHECK-NEXT:    [[START_0:%.*]] = getelementptr inbounds [[STRUCT_1]], ptr [[START]], i64 [[IDX_EXT]], i32 2
 ; CHECK-NEXT:    [[C_0:%.*]] = icmp ult ptr [[START_0]], [[HIGH]]
-; CHECK-NEXT:    ret i1 [[C_0]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       if.end:
 ; CHECK-NEXT:    ret i1 true
 ;
@@ -185,7 +185,7 @@ define i1 @test.ult.true.due.to.second.dimension(ptr %start, ptr %high) {
 ; CHECK-NEXT:    [[START_0:%.*]] = getelementptr inbounds [[STRUCT_1]], ptr [[START]], i64 5, i32 1
 ; CHECK-NEXT:    [[START_0_CAST:%.*]] = bitcast ptr [[START_0]] to ptr
 ; CHECK-NEXT:    [[C_0:%.*]] = icmp ult ptr [[START_0_CAST]], [[HIGH]]
-; CHECK-NEXT:    ret i1 [[C_0]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       if.end:
 ; CHECK-NEXT:    ret i1 true
 ;
@@ -306,7 +306,7 @@ define i1 @ptr.int.struct.test.ult.true.due.to.first.dimension(ptr %start, ptr %
 ; CHECK-NEXT:    [[START_0:%.*]] = getelementptr inbounds [[STRUCT_2]], ptr [[START]], i64 6, i32 0
 ; CHECK-NEXT:    [[START_0_CAST:%.*]] = bitcast ptr [[START_0]] to ptr
 ; CHECK-NEXT:    [[C_0:%.*]] = icmp ult ptr [[START_0_CAST]], [[HIGH]]
-; CHECK-NEXT:    ret i1 [[C_0]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       if.end:
 ; CHECK-NEXT:    ret i1 true
 ;
@@ -340,7 +340,7 @@ define i1 @ptr.int.struct.test.ult.true.due.to.third.dimension.var.index(ptr %st
 ; CHECK-NEXT:    [[START_0:%.*]] = getelementptr inbounds [[STRUCT_2]], ptr [[START]], i64 6, i32 1, i64 [[IDX_EXT]]
 ; CHECK-NEXT:    [[START_0_CAST:%.*]] = bitcast ptr [[START_0]] to ptr
 ; CHECK-NEXT:    [[C_0:%.*]] = icmp ult ptr [[START_0_CAST]], [[HIGH]]
-; CHECK-NEXT:    ret i1 [[C_0]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       if.end:
 ; CHECK-NEXT:    ret i1 true
 ;

diff  --git a/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned.ll b/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned.ll
index a12a40cab23d..2baa6b001d86 100644
--- a/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned.ll
+++ b/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned.ll
@@ -396,7 +396,7 @@ define i1 @cnt_positive_from_assume_check_against_base_struct_ugt_with_zext(ptr
 ; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[CNT]] to i64
 ; CHECK-NEXT:    [[GEP_EXT:%.*]] = getelementptr inbounds [[T:%.*]], ptr [[P:%.*]], i64 0, i32 1, i64 [[EXT]]
 ; CHECK-NEXT:    [[CMP_1:%.*]] = icmp ugt ptr [[GEP_EXT]], [[P]]
-; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK-NEXT:    br i1 true, label [[THEN:%.*]], label [[ELSE:%.*]]
 ; CHECK:       then:
 ; CHECK-NEXT:    ret i1 false
 ; CHECK:       else:
@@ -428,7 +428,7 @@ define i1 @cnt_positive_from_branch_check_against_base_struct_ugt_with_zext(ptr
 ; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[CNT]] to i64
 ; CHECK-NEXT:    [[GEP_EXT:%.*]] = getelementptr inbounds [[T:%.*]], ptr [[P:%.*]], i64 0, i32 1, i64 [[EXT]]
 ; CHECK-NEXT:    [[CMP_1:%.*]] = icmp ugt ptr [[GEP_EXT]], [[P]]
-; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE]]
+; CHECK-NEXT:    br i1 true, label [[THEN:%.*]], label [[ELSE]]
 ; CHECK:       then:
 ; CHECK-NEXT:    ret i1 false
 ; CHECK:       else:


        


More information about the llvm-commits mailing list