Better branch detection model

For loops are now broken up into 2 branches: 1 (init) and 2 (cond + inc).
This commit is contained in:
Erki 2021-03-07 13:02:14 +02:00
parent a23e5c66ab
commit 83ca2deb0e
5 changed files with 103 additions and 53 deletions

View File

@ -115,26 +115,19 @@ void OperationFinder::processArraySubscript(const clang::ArraySubscriptExpr* sub
llvm::outs() << "\n";
}
void OperationFinder::fallthroughBranchEntered()
void OperationFinder::branchEntered()
{
_in_fallthrough = true;
_current_branch++;
llvm::outs() << "Branch entered: " << _current_branch << "\n";
}
void OperationFinder::fallthroughBranchExited()
void OperationFinder::branchExited()
{
_in_fallthrough = false;
}
llvm::outs() << "Branch exited: " << _current_branch << "\n";
void OperationFinder::forLoopEntered()
{
_for_loop_stack.push_back(_next_for_loop_id);
_current_branch--;
_next_for_loop_id++;
}
void OperationFinder::forLoopExited()
{
_for_loop_stack.pop_back();
assert(_current_branch > -1);
}
std::unique_ptr<OperationLog::BasicOperation>
@ -167,8 +160,7 @@ std::pair<std::string, OperationLog> OperationFinder::_createBaseOperationLog(co
OperationLog log;
log.line = line_number;
log.current_for_loops = _for_loop_stack;
log.is_fallthrough = _in_fallthrough;
log.branch_number = _current_branch;
llvm::outs() << file_name << ":"
<< line_number << ":"

View File

@ -19,11 +19,8 @@ public:
void processFunctionCall(const clang::CallExpr* call, const clang::SourceManager& source_manager);
void processArraySubscript(const clang::ArraySubscriptExpr* subscript, const clang::SourceManager& source_manager);
void fallthroughBranchEntered();
void fallthroughBranchExited();
void forLoopEntered();
void forLoopExited();
void branchEntered();
void branchExited();
private:
std::unique_ptr<OperationLog::BasicOperation>
@ -31,9 +28,7 @@ private:
std::pair<std::string, OperationLog> _createBaseOperationLog(const clang::Stmt* stmt, const clang::SourceManager& source_manager);
int _next_for_loop_id = 0;
bool _in_fallthrough = false;
std::vector<int> _for_loop_stack;
int _current_branch = 0;
IOperationOutput* _storage;
};

View File

@ -65,17 +65,10 @@ bool OperationFinderAstVisitor::dataTraverseStmtPre(clang::Stmt* stmt)
{
assert(_context);
if (auto* loop = clang::dyn_cast<clang::ForStmt>(stmt))
if (clang::Stmt* branch_entry = _isBranchEntry(stmt))
{
if (loop->getInit())
{
_loop_init = loop->getInit();
_op_finder->fallthroughBranchEntered();
}
else
{
_op_finder->forLoopEntered();
}
_branch_stack.push_back(branch_entry);
_op_finder->branchEntered();
}
return true;
@ -85,16 +78,77 @@ bool OperationFinderAstVisitor::dataTraverseStmtPost(clang::Stmt* stmt)
{
assert(_context);
if (_loop_init && _loop_init == stmt)
if (_loop_header.in_loop_header && (_loop_header.init == stmt || _loop_header.header_end == stmt))
{
_op_finder->forLoopEntered();
_op_finder->fallthroughBranchExited();
_loop_init = nullptr;
if (_loop_header.header_end == stmt)
{
assert(_branch_stack.back() == stmt);
_branch_stack.pop_back();
_op_finder->branchExited();
if (_loop_header.init)
{
assert(_branch_stack.back() == _loop_header.init);
_branch_stack.pop_back();
_op_finder->branchExited();
}
else if (clang::dyn_cast<clang::ForStmt>(stmt))
_loop_header = {};
}
else if (_loop_header.init == stmt && !_loop_header.header_end)
{
_op_finder->forLoopExited();
assert(_branch_stack.back() == stmt);
_branch_stack.pop_back();
_op_finder->branchExited();
_loop_header = {};
}
}
else if (!_branch_stack.empty() && _branch_stack.back() == stmt)
{
_branch_stack.pop_back();
_op_finder->branchExited();
}
else
{
assert(std::find(_branch_stack.cbegin(), _branch_stack.cend(), stmt)
== _branch_stack.cend());
}
return true;
}
clang::Stmt* OperationFinderAstVisitor::_isBranchEntry(clang::Stmt* stmt)
{
if (auto* loop = clang::dyn_cast<clang::ForStmt>(stmt))
{
_loop_header.init = loop->getInit();
if (loop->getCond())
{
_loop_header.header_start = loop->getCond();
_loop_header.header_end = loop->getCond();
}
if (loop->getInc())
{
if (!_loop_header.header_start)
_loop_header.header_start = loop->getInc();
_loop_header.header_end = loop->getInc();
}
_loop_header.in_loop_header = _loop_header.init || _loop_header.header_end;
if (_loop_header.init)
return _loop_header.init;
else if (_loop_header.header_start)
return _loop_header.header_end;
}
else if (_loop_header.in_loop_header && _loop_header.header_start == stmt)
{
return _loop_header.header_end;
}
return nullptr;
}

View File

@ -30,7 +30,19 @@ private:
clang::ASTContext* _context;
OperationFinder* _op_finder;
clang::Stmt* _loop_init = nullptr;
struct _LoopHeaderStateMachine
{
bool in_loop_header = false;
clang::Stmt* init = nullptr;
clang::Stmt* header_start = nullptr;
clang::Stmt* header_end = nullptr;
};
_LoopHeaderStateMachine _loop_header;
std::vector<clang::Stmt*> _branch_stack;
clang::Stmt* _isBranchEntry(clang::Stmt* stmt);
};
#endif //C_ANALYZER_OPERATIONFINDERASTVISITOR_HPP

View File

@ -39,13 +39,12 @@ struct OperationLog
[[nodiscard]] nlohmann::json toJson() const override;
};
unsigned int line;
unsigned int line = 0;
int branch_number = 0;
std::string entry_type;
std::unique_ptr<IEntry> entry;
bool is_fallthrough;
std::vector<int> current_for_loops;
OperationLog() = default;
OperationLog(const OperationLog&) = delete;
OperationLog(OperationLog&&) = default;
@ -67,8 +66,7 @@ inline void to_json(nlohmann::json& j, const OperationLog& l)
{"line", l.line},
{"entry_type", l.entry_type},
{"entry", l.entry->toJson()},
{"is_fallthrough", l.is_fallthrough},
{"current_for_loops", l.current_for_loops}
{"branch_number", l.branch_number}
};
}
@ -78,8 +76,7 @@ inline void from_json(const nlohmann::json& j, OperationLog& l)
j.at("entry_type").get_to(l.entry_type);
l.DecodeEntry(j["entry"]);
j.at("is_fallthrough").get_to(l.is_fallthrough);
j.at("current_for_loops").get_to(l.current_for_loops);
j.at("branch_number").get_to(l.branch_number);
}
inline void to_json(nlohmann::json& j, const OperationLog::BasicOperation& bo)