mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-28 06:00:28 +00:00
[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:
parent
550e23d356
commit
cfb0063c60
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
83
test/CodeGen/Hexagon/loop-idiom/pmpy-infinite-loop.ll
Normal file
83
test/CodeGen/Hexagon/loop-idiom/pmpy-infinite-loop.ll
Normal 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" }
|
Loading…
Reference in New Issue
Block a user