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"; 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() _current_branch--;
{
_for_loop_stack.push_back(_next_for_loop_id);
_next_for_loop_id++; assert(_current_branch > -1);
}
void OperationFinder::forLoopExited()
{
_for_loop_stack.pop_back();
} }
std::unique_ptr<OperationLog::BasicOperation> std::unique_ptr<OperationLog::BasicOperation>
@ -167,8 +160,7 @@ std::pair<std::string, OperationLog> OperationFinder::_createBaseOperationLog(co
OperationLog log; OperationLog log;
log.line = line_number; log.line = line_number;
log.current_for_loops = _for_loop_stack; log.branch_number = _current_branch;
log.is_fallthrough = _in_fallthrough;
llvm::outs() << file_name << ":" llvm::outs() << file_name << ":"
<< line_number << ":" << line_number << ":"

View File

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

View File

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

View File

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