[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