Skip to content

Commit 40cdf41

Browse files
committed
Fork condition branches
1 parent b51aea5 commit 40cdf41

1 file changed

Lines changed: 63 additions & 57 deletions

File tree

lib/forwardanalyzer.cpp

Lines changed: 63 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ struct ForwardTraversal {
9090
bool isDead() const {
9191
return action.isModified() || action.isInconclusive() || isEscape();
9292
}
93+
bool hasGoto() const {
94+
return endBlock ? ForwardTraversal::hasGoto(endBlock) : false;
95+
}
9396
};
9497

9598
bool stopUpdates() {
@@ -389,6 +392,35 @@ struct ForwardTraversal {
389392
return bail;
390393
}
391394

395+
Progress updateBranch(Branch& branch, int depth)
396+
{
397+
// Save and reset actions
398+
Analyzer::Action prevActions = actions;
399+
actions = Analyzer::Action::None;
400+
Progress p = updateRange(branch.endBlock->link(), branch.endBlock, depth);
401+
branch.action |= actions;
402+
// Restore actions
403+
actions |= prevActions;
404+
405+
if (terminate == Analyzer::Terminate::Escape) {
406+
branch.escape = true;
407+
branch.escapeUnknown = false;
408+
} else if (terminate != Analyzer::Terminate::None) {
409+
if (terminate != Analyzer::Terminate::Escape) {
410+
bool unknown = false;
411+
if (isEscapeScope(branch.endBlock, unknown)) {
412+
branch.escape = true;
413+
branch.escapeUnknown = unknown;
414+
}
415+
}
416+
if (terminate != Analyzer::Terminate::Modified) {
417+
branch.action |= analyzeScope(branch.endBlock);
418+
}
419+
}
420+
421+
return p;
422+
}
423+
392424
bool reentersLoop(Token* endBlock, const Token* condTok, const Token* stepTok) {
393425
if (!condTok)
394426
return true;
@@ -697,71 +729,45 @@ struct ForwardTraversal {
697729
if (!thenBranch.check && !elseBranch.check && analyzer->stopOnCondition(condTok) && stopUpdates())
698730
return Break(Analyzer::Terminate::Conditional);
699731
bool hasElse = Token::simpleMatch(endBlock, "} else {");
700-
bool bail = false;
701-
702-
// Traverse then block
703-
thenBranch.escape = isEscapeScope(endBlock, thenBranch.escapeUnknown);
732+
tok = hasElse ? endBlock->linkAt(2) : endBlock;
704733
if (thenBranch.check) {
705-
thenBranch.active = true;
706-
if (updateRange(endCond->next(), endBlock, depth - 1) == Progress::Break)
734+
if (updateRange(thenBranch.endBlock->link(), thenBranch.endBlock, depth - 1) == Progress::Break)
707735
return Break();
708-
} else if (!elseBranch.check) {
709-
thenBranch.active = true;
710-
if (checkBranch(thenBranch))
711-
bail = true;
712-
}
713-
// Traverse else block
714-
if (hasElse) {
715-
elseBranch.escape = isEscapeScope(endBlock->linkAt(2), elseBranch.escapeUnknown);
716-
if (elseBranch.check) {
717-
elseBranch.active = true;
718-
Progress result = updateRange(endBlock->tokAt(2), endBlock->linkAt(2), depth - 1);
719-
if (result == Progress::Break)
736+
} else if (elseBranch.check) {
737+
if (elseBranch.endBlock && updateRange(elseBranch.endBlock->link(), elseBranch.endBlock, depth - 1) == Progress::Break)
738+
return Break();
739+
} else {
740+
const bool conditional = analyzer->isConditional();
741+
ForwardTraversal ft = fork();
742+
ft.analyzer->assume(condTok, true);
743+
Progress p = ft.updateBranch(thenBranch, depth - 1);
744+
745+
analyzer->assume(condTok, false);
746+
if (hasElse) {
747+
if (updateBranch(elseBranch, depth - 1) == Progress::Break)
720748
return Break();
721-
} else if (!thenBranch.check) {
722-
elseBranch.active = true;
723-
if (checkBranch(elseBranch))
724-
bail = true;
725749
}
726-
tok = endBlock->linkAt(2);
727-
} else {
728-
tok = endBlock;
729-
}
730-
if (thenBranch.active)
731-
actions |= thenBranch.action;
732-
if (elseBranch.active)
733-
actions |= elseBranch.action;
734-
if (bail)
735-
return Break(Analyzer::Terminate::Bail);
736-
if (thenBranch.isDead() && elseBranch.isDead()) {
737-
if (thenBranch.isModified() && elseBranch.isModified())
738-
return Break(Analyzer::Terminate::Modified);
739-
if (thenBranch.isConclusiveEscape() && elseBranch.isConclusiveEscape())
740-
return Break(Analyzer::Terminate::Escape);
741-
return Break(Analyzer::Terminate::Bail);
742-
}
743-
// Conditional return
744-
if (thenBranch.active && thenBranch.isEscape() && !hasElse) {
745-
if (!thenBranch.isConclusiveEscape()) {
750+
if (thenBranch.isDead() || elseBranch.isDead()) {
751+
if (conditional && stopUpdates())
752+
return Break(Analyzer::Terminate::Conditional);
753+
}
754+
if (thenBranch.isModified() || elseBranch.isModified()) {
755+
if (!analyzer->lowerToPossible())
756+
return Break(Analyzer::Terminate::Bail);
757+
if (!ft.analyzer->lowerToPossible())
758+
p = Progress::Break;
759+
}
760+
if (thenBranch.isInconclusive() || elseBranch.isInconclusive()) {
746761
if (!analyzer->lowerToInconclusive())
747762
return Break(Analyzer::Terminate::Bail);
748-
} else if (thenBranch.check) {
749-
return Break();
750-
} else {
751-
if (analyzer->isConditional() && stopUpdates())
752-
return Break(Analyzer::Terminate::Conditional);
753-
analyzer->assume(condTok, false);
763+
if (!ft.analyzer->lowerToInconclusive())
764+
p = Progress::Break;
754765
}
755-
}
756-
if (thenBranch.isInconclusive() || elseBranch.isInconclusive()) {
757-
if (!analyzer->lowerToInconclusive())
766+
if (thenBranch.hasGoto() || elseBranch.hasGoto()) {
758767
return Break(Analyzer::Terminate::Bail);
759-
} else if (thenBranch.isModified() || elseBranch.isModified()) {
760-
if (!hasElse && analyzer->isConditional() && stopUpdates())
761-
return Break(Analyzer::Terminate::Conditional);
762-
if (!analyzer->lowerToPossible())
763-
return Break(Analyzer::Terminate::Bail);
764-
analyzer->assume(condTok, elseBranch.isModified());
768+
}
769+
if (p != Progress::Break)
770+
ft.updateRange(thenBranch.endBlock, end, depth - 1);
765771
}
766772
}
767773
} else if (Token::simpleMatch(tok, "try {")) {

0 commit comments

Comments
 (0)