[ConstraintElimination] Support chained GEPs with constant offsets.
authorFlorian Hahn <flo@fhahn.com>
Sat, 8 Oct 2022 15:59:27 +0000 (16:59 +0100)
committerFlorian Hahn <flo@fhahn.com>
Sat, 8 Oct 2022 15:59:27 +0000 (16:59 +0100)
Handle the (gep (gep ....), C) case by incrementing the constant
coefficient of the inner GEP, if C is a constant.

llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
llvm/test/Transforms/ConstraintElimination/gep-add.ll
llvm/test/Transforms/ConstraintElimination/gep-sub.ll

index 6b7905d..be7939a 100644 (file)
@@ -197,6 +197,25 @@ decompose(Value *V, SmallVector<PreconditionTy, 4> &Preconditions,
     Value *Op0, *Op1;
     ConstantInt *CI;
 
+    // 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()));
+      }
+      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)))) {
index f1f5321..e0fb5c2 100644 (file)
@@ -15,7 +15,7 @@ define i1 @gep_add_1_uge(ptr %dst, ptr %lower) {
 ; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
 ; CHECK-NEXT:    [[DST_ADD_4:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 3
 ; CHECK-NEXT:    [[CMP_ADD_4:%.*]] = icmp uge ptr [[DST_ADD_4]], [[LOWER]]
-; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_ADD_4]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], true
 ; CHECK-NEXT:    ret i1 [[RES_2]]
 ;
   %pre = icmp uge ptr %dst, %lower
@@ -42,7 +42,7 @@ define i1 @gep_add_1_ult(ptr %dst, ptr %lower, ptr %upper) {
 ; CHECK-NEXT:    [[CMP_ADD_3:%.*]] = icmp ult ptr [[DST_ADD_3]], [[UPPER]]
 ; CHECK-NEXT:    [[DST_ADD_4:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_1]], i64 3
 ; CHECK-NEXT:    [[CMP_ADD_4:%.*]] = icmp ult ptr [[DST_ADD_4]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_ADD_3]], [[CMP_ADD_4]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
 ; CHECK-NEXT:    [[DST_ADD_5:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_1]], i64 4
 ; CHECK-NEXT:    [[CMP_ADD_5:%.*]] = icmp ult ptr [[DST_ADD_5]], [[UPPER]]
 ; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_ADD_5]]
@@ -75,7 +75,7 @@ define i1 @gep_add_ult_var_idx(ptr %dst, ptr %upper, i8 %idx) {
 ; CHECK-NEXT:    [[CMP_ADD_1:%.*]] = icmp ule ptr [[DST_ADD_1]], [[UPPER]]
 ; CHECK-NEXT:    [[DST_ADD_2:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_IDX]], i64 2
 ; CHECK-NEXT:    [[CMP_ADD_2:%.*]] = icmp ule ptr [[DST_ADD_2]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_ADD_1]], [[CMP_ADD_2]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, [[CMP_ADD_2]]
 ; CHECK-NEXT:    ret i1 [[RES_1]]
 ;
   %not.zero = icmp ne i8 %idx, 0
@@ -104,7 +104,7 @@ define i1 @gep_add_ult_var_idx_sgt_1(ptr %dst, ptr %upper, i8 %idx) {
 ; CHECK-NEXT:    [[CMP_ADD_1:%.*]] = icmp ule ptr [[DST_ADD_1]], [[UPPER]]
 ; CHECK-NEXT:    [[DST_ADD_2:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_IDX]], i64 2
 ; CHECK-NEXT:    [[CMP_ADD_2:%.*]] = icmp ule ptr [[DST_ADD_2]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_ADD_1]], [[CMP_ADD_2]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, [[CMP_ADD_2]]
 ; CHECK-NEXT:    ret i1 [[RES_1]]
 ;
   %sgt.1 = icmp sgt i8 %idx, 1
@@ -138,7 +138,7 @@ define i1 @gep_add_1_ult_var_idx(ptr %dst, ptr %upper, i8 %len, i8 %idx) {
 ; CHECK-NEXT:    [[CMP_IDX_1:%.*]] = icmp ult ptr [[DST_ADD_IDX_1]], [[UPPER]]
 ; CHECK-NEXT:    [[DST_ADD_IDX_2:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_IDX]], i64 2
 ; CHECK-NEXT:    [[CMP_IDX_2:%.*]] = icmp ult ptr [[DST_ADD_IDX_2]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_IDX_1]], [[CMP_IDX_2]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
 ; CHECK-NEXT:    [[DST_ADD_IDX_3:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_IDX]], i64 3
 ; CHECK-NEXT:    [[CMP_IDX_3:%.*]] = icmp ult ptr [[DST_ADD_IDX_3]], [[UPPER]]
 ; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_IDX_3]]
index 7825d03..ab65d25 100644 (file)
@@ -12,7 +12,7 @@ define i1 @gep_sub_1_uge(ptr %dst, ptr %lower) {
 ; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp uge ptr [[DST_SUB_1]], [[LOWER]]
 ; CHECK-NEXT:    [[DST_SUB_3:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 -3
 ; CHECK-NEXT:    [[CMP_SUB_3:%.*]] = icmp uge ptr [[DST_SUB_3]], [[LOWER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_SUB_1]], [[CMP_SUB_3]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
 ; CHECK-NEXT:    [[DST_SUB_4:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 -4
 ; CHECK-NEXT:    [[CMP_SUB_4:%.*]] = icmp uge ptr [[DST_SUB_4]], [[LOWER]]
 ; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_SUB_4]]
@@ -42,7 +42,7 @@ define i1 @gep_sub_1_ult(ptr %dst, ptr %upper) {
 ; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp ult ptr [[DST_SUB_1]], [[UPPER]]
 ; CHECK-NEXT:    [[DST_SUB_3:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 -3
 ; CHECK-NEXT:    [[CMP_SUB_3:%.*]] = icmp ult ptr [[DST_SUB_3]], [[UPPER]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_SUB_1]], [[CMP_SUB_3]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
 ; CHECK-NEXT:    ret i1 [[RES_1]]
 ;
   %dst.add.4 = getelementptr inbounds i8, ptr %dst, i64 4