[ConstraintElimination] Bail out if system gets too big.
authorFlorian Hahn <flo@fhahn.com>
Sun, 6 Dec 2020 19:58:33 +0000 (19:58 +0000)
committerFlorian Hahn <flo@fhahn.com>
Sun, 6 Dec 2020 20:19:15 +0000 (20:19 +0000)
For some inputs, the constraint system can grow quite large during
solving, because it replaces complex constraints with one or more
simpler constraints. This adds a cut-off to avoid compile-time explosion
on problematic inputs.

llvm/include/llvm/Analysis/ConstraintSystem.h
llvm/lib/Analysis/ConstraintSystem.cpp
llvm/test/Transforms/ConstraintElimination/large-system-growth.ll [new file with mode: 0644]

index 2e55d5d..83c1fb4 100644 (file)
@@ -79,6 +79,9 @@ public:
   bool isConditionImplied(SmallVector<int64_t, 8> R);
 
   void popLastConstraint() { Constraints.pop_back(); }
+
+  /// Returns the number of rows in the constraint system.
+  unsigned size() const { return Constraints.size(); }
 };
 } // namespace llvm
 
index f3a2834..1d58280 100644 (file)
@@ -84,6 +84,9 @@ bool ConstraintSystem::eliminateUsingFM() {
                      .getZExtValue();
       }
       NewSystem.push_back(std::move(NR));
+      // Give up if the new system gets too big.
+      if (NewSystem.size() > 500)
+        return false;
     }
   }
   Constraints = std::move(NewSystem);
diff --git a/llvm/test/Transforms/ConstraintElimination/large-system-growth.ll b/llvm/test/Transforms/ConstraintElimination/large-system-growth.ll
new file mode 100644 (file)
index 0000000..e2d603e
--- /dev/null
@@ -0,0 +1,86 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -constraint-elimination -S %s | FileCheck %s
+
+; The system for the function below grows quite large. Check to make sure
+; we can handle that scenario.
+define void @test(i64 %x, i8* %y, i8* %z, i8* %w) {
+; CHECK-LABEL: @test(
+; CHECK-NEXT:    [[TMP22:%.*]] = getelementptr inbounds i8, i8* [[Y:%.*]], i64 [[X:%.*]]
+; CHECK-NEXT:    [[TMP26:%.*]] = icmp ult i8* [[TMP22]], [[Z:%.*]]
+; CHECK-NEXT:    br i1 [[TMP26]], label [[BB28:%.*]], label [[EARLY_EXIT:%.*]]
+; CHECK:       early.exit:
+; CHECK-NEXT:    unreachable
+; CHECK:       bb28:
+; CHECK-NEXT:    [[TMP29:%.*]] = getelementptr inbounds i8, i8* [[Y]], i64 [[X]]
+; CHECK-NEXT:    [[TMP30:%.*]] = icmp ult i8* [[TMP29]], [[Z]]
+; CHECK-NEXT:    br i1 true, label [[EARLY_EXIT]], label [[BB32:%.*]]
+; CHECK:       bb32:
+; CHECK-NEXT:    [[TMP33:%.*]] = icmp ult i8* [[TMP29]], [[Z]]
+; CHECK-NEXT:    br i1 true, label [[BB35:%.*]], label [[EARLY_EXIT]]
+; CHECK:       bb35:
+; CHECK-NEXT:    [[TMP36:%.*]] = icmp ult i8* [[Y]], [[Z]]
+; CHECK-NEXT:    br i1 true, label [[EARLY_EXIT]], label [[BB38:%.*]]
+; CHECK:       bb38:
+; CHECK-NEXT:    [[TMP41:%.*]] = icmp ult i8* [[Y]], [[Z]]
+; CHECK-NEXT:    br i1 true, label [[EARLY_EXIT]], label [[BB43:%.*]]
+; CHECK:       bb43:
+; CHECK-NEXT:    [[TMP47:%.*]] = getelementptr inbounds i8, i8* [[W:%.*]], i64 [[X]]
+; CHECK-NEXT:    [[TMP48:%.*]] = icmp ult i8* [[TMP47]], [[Y]]
+; CHECK-NEXT:    br i1 [[TMP48]], label [[EARLY_EXIT]], label [[BB50:%.*]]
+; CHECK:       bb50:
+; CHECK-NEXT:    [[TMP52:%.*]] = getelementptr inbounds i8, i8* [[W]], i64 [[X]]
+; CHECK-NEXT:    [[TMP53:%.*]] = icmp ult i8* [[TMP52]], [[Y]]
+; CHECK-NEXT:    br i1 true, label [[EARLY_EXIT]], label [[BB55:%.*]]
+; CHECK:       bb55:
+; CHECK-NEXT:    [[TMP57:%.*]] = icmp ult i8* [[W]], [[Y]]
+; CHECK-NEXT:    br i1 true, label [[BB59:%.*]], label [[EARLY_EXIT]]
+; CHECK:       bb59:
+; CHECK-NEXT:    [[TMP60:%.*]] = icmp ult i8* [[W]], [[Y]]
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    ret void
+;
+  %tmp22 = getelementptr inbounds i8, i8* %y, i64 %x
+  %tmp26 = icmp ult i8* %tmp22, %z
+  br i1 %tmp26, label %bb28, label %early.exit
+
+early.exit:
+  unreachable
+
+bb28:
+  %tmp29 = getelementptr inbounds i8, i8* %y, i64 %x
+  %tmp30 = icmp ult i8* %tmp29, %z
+  br i1 %tmp30, label %early.exit, label %bb32
+
+bb32:
+  %tmp33 = icmp ult i8* %tmp29, %z
+  br i1 %tmp33, label %bb35, label %early.exit
+
+bb35:
+  %tmp36 = icmp ult i8* %y, %z
+  br i1 %tmp36, label %early.exit, label %bb38
+
+bb38:
+  %tmp41 = icmp ult i8* %y, %z
+  br i1 %tmp41, label %early.exit, label %bb43
+
+bb43:
+  %tmp47 = getelementptr inbounds i8, i8* %w, i64 %x
+  %tmp48 = icmp ult i8* %tmp47, %y
+  br i1 %tmp48, label %early.exit, label %bb50
+
+bb50:
+  %tmp52 = getelementptr inbounds i8, i8* %w, i64 %x
+  %tmp53 = icmp ult i8* %tmp52, %y
+  br i1 %tmp53, label %early.exit, label %bb55
+
+bb55:
+  %tmp57 = icmp ult i8* %w, %y
+  br i1 %tmp57, label %bb59, label %early.exit
+
+bb59:
+  %tmp60 = icmp ult i8* %w, %y
+  call void @use(i1 %tmp60)
+  ret void
+}
+
+declare void @use(i1)