systemc-clang 2.0.0
Parsing SystemC constructs
Loading...
Searching...
No Matches
SensitivityMatcher.h
Go to the documentation of this file.
1//===- SensitivityMatcher.h - Matching sensitivity lists --*- C++ -*-=====//
2//
3// Part of the systemc-clang project.
4// See License.rst
5//
6//===----------------------------------------------------------------------===//
7//
10//
12//===----------------------------------------------------------------------===//
13
14#ifndef _SENSITIVITY_MATCHER_H_
15#define _SENSITIVITY_MATCHER_H_
16
17#include <map>
18#include <vector>
19
20// Clang includes.
21//
22#include "clang/ASTMatchers/ASTMatchFinder.h"
23#include "clang/ASTMatchers/ASTMatchers.h"
24#include "llvm/Support/Debug.h"
25
26#include "ArrayTypeUtils.h"
28#undef DEBUG_TYPE
29#define DEBUG_TYPE "SensitivityMatcher"
30
31namespace sc_ast_matchers {
32using namespace clang::ast_matchers;
42class CallerCalleeMatcher : public MatchFinder::MatchCallback {
43 private:
47 typedef std::vector<
48 std::tuple<std::string, clang::ValueDecl *, clang::MemberExpr *,
49 clang::VarDecl *, clang::ArraySubscriptExpr *, clang::ForStmt*>>
51
53 std::vector<std::tuple<std::string, clang::ValueDecl *, clang::MemberExpr *,
54 clang::VarDecl *, clang::ArraySubscriptExpr *, clang::ForStmt*>>
56
57 clang::VarDecl *vd_;
58
59 public:
62
64 void registerMatchers(MatchFinder &finder, clang::VarDecl *vd) {
65 vd_ = vd;
66
67 /* clang-format off */
68
70 auto match_member_expr = findAll(memberExpr().bind("me"));
71
72 /* clang-format on */
73 finder.addMatcher(match_member_expr, this);
74 }
75
77 virtual void run(const MatchFinder::MatchResult &result) {
78 auto me{const_cast<clang::MemberExpr *>(
79 result.Nodes.getNodeAs<clang::MemberExpr>("me"))};
80
81 if (me) {
82 std::string name{me->getMemberDecl()->getNameAsString()};
83 calls_.insert(calls_.begin(), std::make_tuple(name, me->getMemberDecl(),
84 me, vd_, nullptr, nullptr));
85 }
86 }
87
89 void dump() {
90 for (auto const &call : calls_) {
91 (llvm::outs() << std::get<0>(call) << " " << std::get<1>(call) << " "
92 << std::get<2>(call) << "\n");
93 }
94 }
95};
96
102class SensitiveOperatorCallMatcher : public MatchFinder::MatchCallback {
103 private:
104 clang::CXXMemberCallExpr *cxx_mcall_;
105 clang::MemberExpr *me_wo_mcall_;
106 const clang::ArraySubscriptExpr *array_fd_;
107
108 public:
109 clang::CXXMemberCallExpr *getMemberExprCallExpr() { return cxx_mcall_; }
110
111 clang::MemberExpr *getMemberExprWithoutCall() { return me_wo_mcall_; }
112 const clang::ArraySubscriptExpr *getMemberArraySubscriptExpr() {
113 return array_fd_;
114 }
115
135
136 void registerMatchers(MatchFinder &finder) {
137 /* clang-format off */
138
139 auto match_opcall=
140 cxxOperatorCallExpr(
141 // Match sc_event_finder argument
142 hasArgument(1,
143 allOf(
144 anyOf(
145 memberExpr(
146 hasDeclaration(
147 fieldDecl().bind("fd")
148 ) //hasDeclaration
149 ).bind("me")
150 ,
151 cxxMemberCallExpr().bind("cxx_mcall")
152 ,
153 arraySubscriptExpr().bind("array_fd")
154 ) // anyOf
155 ,
156 anyOf(
157 hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
158 cxxRecordDecl(isSameOrDerivedFrom("sc_event")).bind("crd")))))
159 , hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
160 cxxRecordDecl(isSameOrDerivedFrom("sc_interface")).bind("crd")))))
161 , hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
162 cxxRecordDecl(isSameOrDerivedFrom("sc_event_finder")).bind("crd")))))
163 , hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
164 cxxRecordDecl(isSameOrDerivedFrom("sc_port_base")).bind("crd")))))
165 )//anyOf
166 ) // allOf
167 ) //hasArgument
168 ,
169 // Match only those that are of sc_sensitive class
170 hasType(hasUnqualifiedDesugaredType(
171 recordType(hasDeclaration(cxxRecordDecl(isSameOrDerivedFrom("sc_sensitive"))))
172 )//hasUnqualifiedDesugaredType
173 )// hasType
174 ).bind("cxx_operator_call_expr");
175
177
178 finder.addMatcher(match_opcall, this);
179 }
180
181 virtual void run(const MatchFinder::MatchResult &result) {
182 LLVM_DEBUG(llvm::dbgs() << "#### OperatorCallMatcher\n");
183
184 auto array_fd{result.Nodes.getNodeAs<clang::ArraySubscriptExpr>("array_fd")};
185
186 if (array_fd) {
187 array_fd_ = array_fd;
188 }
189
190 auto cxxcall{result.Nodes.getNodeAs<clang::CXXOperatorCallExpr>("cxx_operator_call_expr")};
191 // LLVM_DEBUG(cxxcall->dump());
192
193 auto cxx_mcall{const_cast<clang::CXXMemberCallExpr*>(
194 result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("cxx_mcall"))};
195 auto me_wo_mcall{
196 const_cast<clang::MemberExpr*>(result.Nodes.getNodeAs<clang::MemberExpr>("me"))};
197
198 if (cxx_mcall) { cxx_mcall_ = cxx_mcall; }
199 if (me_wo_mcall) { me_wo_mcall_ = me_wo_mcall; }
200 }
201};
202
203
204
206//
208//
209//
211class SensitivityMatcher : public MatchFinder::MatchCallback {
212 public:
218
219 typedef std::tuple<std::string, clang::ValueDecl*, clang::MemberExpr*, clang::VarDecl*, clang::ArraySubscriptExpr*, clang::ForStmt*>
221
223 typedef std::pair<std::string, std::vector<SensitivityTupleType>>
225
227 //typedef std::map<std::string, std::vector<SensitivityTupleType>> SenseMapType;
228 typedef std::map<std::string, std::vector<SensitivityTupleType>> SenseMapType;
229
230 private:
233
235 clang::VarDecl *process_handle_;
236
239 const std::vector<SensitivityTupleType> &sense_args) {
240 std::string name{};
241 std::string ef_name{};
242 for (auto const entry : sense_args) {
243 name = name + std::get<0>(entry);
244 auto vd{std::get<3>(entry)};
245 if (vd) { ef_name = vd->getNameAsString();}
246 }
247 return ef_name+"__"+name;
248 }
249
250 public:
256
259 void registerMatchers(MatchFinder &finder) {
260 /* clang-format off */
261
262 auto NoNestedFor = forStmt(unless(hasDescendant(forStmt())), unless(hasAncestor(forStmt()))).bind("for_stmt");
263 // Detect the variable declared for the process' handle.
264 auto scProcessType = hasType(hasUnqualifiedDesugaredType(recordType()));
265 auto processHandle = hasDescendant(valueDecl(scProcessType).bind("proc_vd"));
266 // Operator call that is <b>not</b> in a for statement.
267 auto operatorCall = forEachDescendant(cxxOperatorCallExpr( ).bind("opcall"));
268 // Operator call that is <b>within</b> a for statement. Note that only one for statement is supported.
269 auto sensitivityInOneLoop = forStmt(operatorCall).bind("for_stmt");
270
271 auto match_single_for =
272 cxxConstructorDecl(
273 has(
274 compoundStmt(
275 processHandle,
276 eachOf (
277 forEachDescendant(sensitivityInOneLoop) // ForEachDescendant
278 ,
279 allOf(operatorCall, unless(sensitivityInOneLoop))
280 ) //anyOf
281 ).bind("compound_stmt")
282 )
283 ).bind("cxx_constructor_decl");
284
285
286 // auto match_original =
287 // cxxConstructorDecl(
288 // has(
289 // compoundStmt(
290 // forEachDescendant(
291 // cxxOperatorCallExpr(optionally(
292 // hasDescendant(declRefExpr(hasType(cxxRecordDecl(hasName("::sc_core::sc_process_handle")))).bind("process_handle"))
293 // )
294 // ).bind("opcall")
295 // )
296 // ).bind("compound_stmt")
297 // )
298 // ).bind("cxx_constructor_decl");
299//
300 /* clang-format on */
302 // finder.addMatcher(match_original, this);
303 finder.addMatcher(match_single_for, this);
304 }
305
307 virtual void run(const MatchFinder::MatchResult &result) {
308 // LLVM_DEBUG(llvm::dbgs()
309 DEBUG_WITH_TYPE("matcher-header",
310 llvm::dbgs()
311 << "====== SENSITIVITY MATCHER EXECUTED ======= \n");
312
313 clang::CXXMemberCallExpr *cxx_mcall{};
314 clang::MemberExpr *me_wo_mcall{};
315 clang::ArraySubscriptExpr *array_expr{};
316
318 auto proc_vd{const_cast<clang::VarDecl *>(
319 result.Nodes.getNodeAs<clang::VarDecl>("proc_vd"))};
320 auto proc_handle = proc_vd;
321
322 auto cons_decl{const_cast<clang::CXXConstructorDecl *>(
323 result.Nodes.getNodeAs<clang::CXXConstructorDecl>(
324 "cxx_constructor_decl"))};
325 auto opcall{const_cast<clang::CXXOperatorCallExpr *>(
326 result.Nodes.getNodeAs<clang::CXXOperatorCallExpr>("opcall"))};
327 auto for_stmt{const_cast<clang::ForStmt *>(
328 result.Nodes.getNodeAs<clang::ForStmt>("for_stmt"))};
329
330
331 if (opcall) {
332 LLVM_DEBUG(
333
334 if (cons_decl) {
335 cons_decl->dump();
336 }
337 // Check if there is process handle
338 if (proc_vd) {
339 llvm::dbgs() << "# proc_vd " << " " << proc_vd->getNameAsString() << "\n";
340 process_handle_ = proc_vd;
341 opcall->dump();
342 }
343
344 if (for_stmt) {
345 LLVM_DEBUG(llvm::dbgs() << "# ForStmt \n";
346 for_stmt->getInit()->dump(););
347 }
348 ); // LLVM_DEBUG
349
350 MatchFinder sense_registry{};
351 SensitiveOperatorCallMatcher sop_matcher{};
352 sop_matcher.registerMatchers(sense_registry);
353 sense_registry.match(*opcall, *result.Context);
354
355 cxx_mcall = sop_matcher.getMemberExprCallExpr();
356 me_wo_mcall = sop_matcher.getMemberExprWithoutCall();
357 array_expr = const_cast<clang::ArraySubscriptExpr *>(
358 sop_matcher.getMemberArraySubscriptExpr());
359
360 LLVM_DEBUG(
361 if (cxx_mcall) {
362 llvm::dbgs() << "cxx_mcall is true; ";
363 } if (me_wo_mcall) {
364 llvm::dbgs() << "me_wo_mcall is true; ";
365 } if (array_expr) { llvm::dbgs() << "array_expr is true; "; }
366 );
367 }
368
373
374 if (process_handle_) {
375 if (me_wo_mcall) {
376 MatchFinder call_registry{};
377 CallerCalleeMatcher call_matcher{};
378 call_matcher.registerMatchers(call_registry, process_handle_);
379 call_registry.match(*me_wo_mcall, *result.Context);
380
381 // LLVM_DEBUG(call_matcher.dump());
382 auto entry{call_matcher.getCallerCallee()};
383 sensitivity_.insert(
385 }
386
390 if (cxx_mcall) {
391 MatchFinder call_registry{};
392 CallerCalleeMatcher call_matcher{};
393 call_matcher.registerMatchers(call_registry, process_handle_);
394 call_registry.match(*cxx_mcall, *result.Context);
395
396 auto entry{call_matcher.getCallerCallee()};
397 sensitivity_.insert(
399 }
400
403 if (array_expr) {
404 auto me{getArrayMemberExprName(array_expr)};
405 std::string name{me->getMemberDecl()->getNameAsString()};
406 auto entry{std::make_tuple(name, me->getMemberDecl(),
407 const_cast<clang::MemberExpr *>(me),
408 process_handle_, array_expr)};
409 std::vector<SensitivityTupleType> calls;
410
411 // std::tuple<std::string, clang::ValueDecl *, clang::MemberExpr *,
412 // clang::VarDecl *, clang::ArraySubscriptExpr *>>
413 // calls;
414 calls.insert(calls.begin(),
415 std::make_tuple(name, me->getMemberDecl(),
416 const_cast<clang::MemberExpr *>(me),
417 process_handle_, array_expr, for_stmt));
418
419 sensitivity_.insert(
421 }
422 }
423 LLVM_DEBUG(dump());
424 }
425
429 void dump() {
430 for (auto const entry : sensitivity_) {
431 auto generated_name{entry.first};
432 auto callercallee{entry.second};
433 LLVM_DEBUG(llvm::dbgs()
434 << "generated name is " << generated_name << " \n");
435
436 for (auto const &call : callercallee) {
437 clang::VarDecl *vd{std::get<3>(call)};
438 clang::ForStmt *fs{std::get<5>(call)};
439
440 LLVM_DEBUG(llvm::dbgs()
441 << "sensitive signal is " << std::get<0>(call) << " "
442 << std::get<1>(call) << " " << std::get<2>(call) << "\n");
443 if (fs) {
444 llvm::dbgs() << "within a for statement \n";
445 fs->getInit()->dump();
446 }
447
448 if (auto array_expr = std::get<4>(call)) {
449 LLVM_DEBUG(llvm::dbgs() << "ArraySubscriptExpr\n";
450 array_expr->dump(););
451 llvm::dbgs() << "Print subscripts\n";
452 std::vector<const clang::Expr *> arr_subs{
453 getArraySubscripts(array_expr)};
454 for (auto const &ex : arr_subs) {
455 ex->dump();
456 }
457 }
458 }
459 }
460
461 }
462};
463}; // namespace sc_ast_matchers
464#endif
void dump()
Dump out the caller and callee found in the sensitivity list.
CallerCalleeType getCallerCallee() const
This returns a list of all the caller and callees that are identified.
virtual void run(const MatchFinder::MatchResult &result)
This is the callback function when there is a match.
void registerMatchers(MatchFinder &finder, clang::VarDecl *vd)
Register the matchers to identify caller and callees.
std::vector< std::tuple< std::string, clang::ValueDecl *, clang::MemberExpr *, clang::VarDecl *, clang::ArraySubscriptExpr *, clang::ForStmt * > > CallerCalleeType
std::vector< std::tuple< std::string, clang::ValueDecl *, clang::MemberExpr *, clang::VarDecl *, clang::ArraySubscriptExpr *, clang::ForStmt * > > calls_
Store the information.
virtual void run(const MatchFinder::MatchResult &result)
const clang::ArraySubscriptExpr * getMemberArraySubscriptExpr()
const clang::ArraySubscriptExpr * array_fd_
virtual void run(const MatchFinder::MatchResult &result)
This is the callback function whenever there is a match.
std::pair< std::string, std::vector< SensitivityTupleType > > SensitivityPairType
This is the pair for inserting key-value entries in the map.
std::map< std::string, std::vector< SensitivityTupleType > > SenseMapType
The key is going to be the name of the FieldDecl/VarDecl.
std::tuple< std::string, clang::ValueDecl *, clang::MemberExpr *, clang::VarDecl *, clang::ArraySubscriptExpr *, clang::ForStmt * > SensitivityTupleType
clang::VarDecl * process_handle_
This provides access to the SystemC process' entry function handler.
void registerMatchers(MatchFinder &finder)
Defines the matcher, and setup the matcher.
SenseMapType getSensitivityMap()
Return the sensitivity map that has been created.
void dump()
Dump out the detected sensitivity list for every process.
std::string generateSensitivityName(const std::vector< SensitivityTupleType > &sense_args)
This generates an encoded name of the argument for the sensitivity.
SenseMapType sensitivity_
This is the map structure to store the identified sensitivity list.
ArraySizesExprType getArraySubscripts(const clang::Expr *expr)
const clang::MemberExpr * getArrayMemberExprName(const clang::Expr *expr)