[Hexagon] Avoid infinite loops in HexagonLoopIdiomRecognition

- Avoid explosive growth of the simplification queue by not queuing
  expressions that are alredy in it.
- Add an iteration counter and abort after a sufficiently large number
  of iterations (assuming that it's a symptom of an infinite loop).


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@298655 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Krzysztof Parzyszek 2017-03-23 23:01:22 +00:00
parent 550e23d356
commit cfb0063c60
2 changed files with 112 additions and 13 deletions

View File

@ -136,7 +136,24 @@ namespace {
void addRule(const Rule &R) { Rules.push_back(R); } void addRule(const Rule &R) { Rules.push_back(R); }
private: private:
typedef std::deque<Value*> WorkListType; struct WorkListType {
WorkListType() = default;
void push_back(Value* V) {
// Do not push back duplicates.
if (!S.count(V)) { Q.push_back(V); S.insert(V); }
}
Value *pop_front_val() {
Value *V = Q.front(); Q.pop_front(); S.erase(V);
return V;
}
bool empty() const { return Q.empty(); }
private:
std::deque<Value*> Q;
std::set<Value*> S;
};
typedef std::set<Value*> ValueSetType; typedef std::set<Value*> ValueSetType;
std::vector<Rule> Rules; std::vector<Rule> Rules;
@ -199,8 +216,7 @@ void Simplifier::Context::traverse(Value *V, FuncT F) {
Q.push_back(V); Q.push_back(V);
while (!Q.empty()) { while (!Q.empty()) {
Instruction *U = dyn_cast<Instruction>(Q.front()); Instruction *U = dyn_cast<Instruction>(Q.pop_front_val());
Q.pop_front();
if (!U || U->getParent()) if (!U || U->getParent())
continue; continue;
if (!F(U)) if (!F(U))
@ -248,8 +264,7 @@ void Simplifier::Context::initialize(Instruction *Exp) {
Q.push_back(Exp); Q.push_back(Exp);
while (!Q.empty()) { while (!Q.empty()) {
Value *V = Q.front(); Value *V = Q.pop_front_val();
Q.pop_front();
if (M.find(V) != M.end()) if (M.find(V) != M.end())
continue; continue;
if (Instruction *U = dyn_cast<Instruction>(V)) { if (Instruction *U = dyn_cast<Instruction>(V)) {
@ -320,8 +335,7 @@ Value *Simplifier::Context::subst(Value *Tree, Value *OldV, Value *NewV) {
WorkListType Q; WorkListType Q;
Q.push_back(Tree); Q.push_back(Tree);
while (!Q.empty()) { while (!Q.empty()) {
Instruction *U = dyn_cast<Instruction>(Q.front()); Instruction *U = dyn_cast<Instruction>(Q.pop_front_val());
Q.pop_front();
// If U is not an instruction, or it's not a clone, skip it. // If U is not an instruction, or it's not a clone, skip it.
if (!U || U->getParent()) if (!U || U->getParent())
continue; continue;
@ -355,8 +369,7 @@ void Simplifier::Context::replace(Value *OldV, Value *NewV) {
WorkListType Q; WorkListType Q;
Q.push_back(NewV); Q.push_back(NewV);
while (!Q.empty()) { while (!Q.empty()) {
Value *V = Q.front(); Value *V = Q.pop_front_val();
Q.pop_front();
Instruction *U = dyn_cast<Instruction>(V); Instruction *U = dyn_cast<Instruction>(V);
if (!U || U->getParent()) if (!U || U->getParent())
continue; continue;
@ -421,8 +434,7 @@ Value *Simplifier::Context::find(Value *Tree, Value *Sub) const {
Q.push_back(Tree); Q.push_back(Tree);
while (!Q.empty()) { while (!Q.empty()) {
Value *V = Q.front(); Value *V = Q.pop_front_val();
Q.pop_front();
if (V == Sub) if (V == Sub)
return V; return V;
Instruction *U = dyn_cast<Instruction>(V); Instruction *U = dyn_cast<Instruction>(V);
@ -463,10 +475,13 @@ Value *Simplifier::Context::materialize(BasicBlock *B,
Value *Simplifier::simplify(Context &C) { Value *Simplifier::simplify(Context &C) {
WorkListType Q; WorkListType Q;
Q.push_back(C.Root); Q.push_back(C.Root);
unsigned Count = 0;
const unsigned Limit = 100000;
while (!Q.empty()) { while (!Q.empty()) {
Instruction *U = dyn_cast<Instruction>(Q.front()); if (Count++ >= Limit)
Q.pop_front(); break;
Instruction *U = dyn_cast<Instruction>(Q.pop_front_val());
if (!U || U->getParent() || !C.Used.count(U)) if (!U || U->getParent() || !C.Used.count(U))
continue; continue;
bool Changed = false; bool Changed = false;
@ -485,6 +500,7 @@ Value *Simplifier::simplify(Context &C) {
Q.push_back(Op); Q.push_back(Op);
} }
} }
assert(Count < Limit && "Infinite loop in HLIR/simplify?");
return C.Root; return C.Root;
} }

View File

@ -0,0 +1,83 @@
; RUN: opt -march=hexagon -hexagon-loop-idiom -S < %s | FileCheck %s
; CHECK-LABEL: define void @fred
; Check that this test does not crash.
target datalayout = "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048"
target triple = "hexagon"
%struct.0 = type { [120 x i16], [80 x i16], [80 x i16], [80 x i16], [80 x i16], [80 x i16], [40 x i16], [40 x i16], [40 x i16], [40 x i16], [40 x i16], [40 x i16] }
define void @fred(%struct.0* %demod_state) local_unnamed_addr #0 {
entry:
br label %for.body309
for.body309: ; preds = %for.body309, %entry
%max_diff.0300 = phi i16 [ %max_diff.1, %for.body309 ], [ 0, %entry ]
%arrayidx322.phi = phi i16* [ undef, %entry ], [ %arrayidx322.inc, %for.body309 ]
%arrayidx331.phi = phi i16* [ undef, %entry ], [ %arrayidx331.inc, %for.body309 ]
%lag.4299.apmt = phi i32 [ %inc376.apmt, %for.body309 ], [ 0, %entry ]
%0 = load i16, i16* %arrayidx322.phi, align 2
%conv323 = sext i16 %0 to i32
%sub324 = sub nsw i32 0, %conv323
%ispos258 = icmp sgt i32 %sub324, -1
%1 = select i1 %ispos258, i32 %sub324, i32 0
%add326 = add nsw i32 %1, 0
%2 = load i16, i16* %arrayidx331.phi, align 2
%conv332 = sext i16 %2 to i32
%sub333 = sub nsw i32 0, %conv332
%ispos260 = icmp sgt i32 %sub333, -1
%3 = select i1 %ispos260, i32 %sub333, i32 undef
%sub342 = sub nsw i32 0, %conv323
%ispos262 = icmp sgt i32 %sub342, -1
%4 = select i1 %ispos262, i32 %sub342, i32 undef
%sub351 = sub nsw i32 0, %conv332
%ispos264 = icmp sgt i32 %sub351, -1
%5 = select i1 %ispos264, i32 %sub351, i32 0
%sub360 = sub nsw i32 %conv323, %conv332
%ispos266 = icmp sgt i32 %sub360, -1
%6 = select i1 %ispos266, i32 %sub360, i32 0
%add335 = add nsw i32 %add326, %4
%add344 = add nsw i32 %add335, %3
%add353 = add i32 %add344, %5
%add362 = add i32 %add353, %6
%div363 = sdiv i32 %add362, 6
%conv364 = trunc i32 %div363 to i16
%sext268 = shl i32 %div363, 16
%conv369 = ashr exact i32 %sext268, 16
%conv370 = sext i16 %max_diff.0300 to i32
%cmp371 = icmp sgt i32 %conv369, %conv370
%max_diff.1 = select i1 %cmp371, i16 %conv364, i16 %max_diff.0300
%inc376.apmt = add nuw nsw i32 %lag.4299.apmt, 1
%exitcond331 = icmp ne i32 %inc376.apmt, 40
%arrayidx322.inc = getelementptr i16, i16* %arrayidx322.phi, i32 1
%arrayidx331.inc = getelementptr i16, i16* %arrayidx331.phi, i32 1
br i1 %exitcond331, label %for.body309, label %for.end377
for.end377: ; preds = %for.body309
%max_diff.1.lcssa = phi i16 [ %max_diff.1, %for.body309 ]
%cmp407 = icmp sgt i16 %max_diff.1.lcssa, 4
br label %for.body405
for.body405: ; preds = %if.end437, %for.end377
%arrayidx412 = getelementptr inbounds %struct.0, %struct.0* %demod_state, i32 0, i32 11, i32 undef
br i1 %cmp407, label %if.then409, label %if.end437
if.then409: ; preds = %for.body405
%arrayidx416 = getelementptr inbounds [40 x i16], [40 x i16]* null, i32 0, i32 undef
%7 = load i16, i16* %arrayidx416, align 2
%conv417 = sext i16 %7 to i32
%shl = shl i32 %conv417, 4
%mul419 = mul nsw i32 %shl, 655
%add420 = add nsw i32 %mul419, 0
br label %if.end437
if.end437: ; preds = %if.then409, %for.body405
%mul431.sink = phi i32 [ %add420, %if.then409 ], [ undef, %for.body405 ]
%shr432257 = lshr i32 %mul431.sink, 15
%conv433 = trunc i32 %shr432257 to i16
store i16 %conv433, i16* %arrayidx412, align 2
br label %for.body405
}
attributes #0 = { noinline nounwind "target-cpu"="hexagonv60" "target-features"="-hvx-double,-long-calls" }