systemc-clang 2.0.0
Parsing SystemC constructs
Loading...
Searching...
No Matches
PortMatcher.h
Go to the documentation of this file.
1//===- PortMatcher.h - Matching Ports -------------------------*- C++ -*-=====//
2//
3// Part of the systemc-clang project.
4// See License.rst
5//
6//===----------------------------------------------------------------------===//
7//
10//
12//===----------------------------------------------------------------------===//
13
14#ifndef _PORT_MATCHER_H_
15#define _PORT_MATCHER_H_
16
17#include <vector>
18#include "ModuleInstance.h"
19#include "PortDecl.h"
20#include "ArrayTypeUtils.h"
21
22#include "clang/ASTMatchers/ASTMatchers.h"
23
25#undef DEBUG_TYPE
26#define DEBUG_TYPE "PortMatcher"
27
28using namespace clang::ast_matchers;
29
30namespace sc_ast_matchers {
31
32using namespace utils::array_type;
33
35//
37//
42
43class PortMatcher : public MatchFinder::MatchCallback {
44 public:
47 typedef std::vector<std::tuple<std::string, PortDecl *> > MemberDeclType;
48
49 private:
50 //std::string top_module_decl_;
51
52 public:
63
66
67 public:
68
71 const MemberDeclType &getClockPorts() const { return clock_ports_; }
72
75 const MemberDeclType &getInputPorts() const { return in_ports_; }
76
79 const MemberDeclType &getOutputPorts() const { return out_ports_; }
80
83 const MemberDeclType &getInOutPorts() const { return inout_ports_; }
84
87 const MemberDeclType &getOtherVars() const { return other_fields_; }
88
91 const MemberDeclType &getSignals() const { return signal_fields_; }
92
95 const MemberDeclType &getSubmodules() const { return submodules_; }
96
100
104 return outstream_ports_;
105 }
106
108 const MemberDeclType &getPorts() const { return sc_ports_; }
109
112
114 auto makeFieldMatcher(llvm::StringRef name) {
115 /* clang-format off */
116
122 return cxxRecordDecl(
123 isExpansionInMainFile(),
124 isDerivedFrom(hasName("::sc_core::sc_module")),
125 forEach(
126 fieldDecl(hasType(
127 cxxRecordDecl(hasName(name))
128 ) // hasType
129 ).bind(name) // fieldDecl
130 )
131 );
132 }
133
141 auto makeSignalArrayType(const std::string &name) {
142 return arrayType(
143 hasElementType(
144 hasDeclaration(
145 cxxRecordDecl(isDerivedFrom(hasName(name))).bind("desugar_"+name)
146 )
147 )
148 ).bind("array_type");
149 }
150
151 auto signalMatcher(const std::string &name) {
152 return anyOf(
153 hasType(makeSignalArrayType(name))
154 ,
155 // 2-d
156 hasType(
157 arrayType(
158 //hasElementType(
159 hasElementType(hasUnqualifiedDesugaredType(
161 )//hasElementType
162 )
163 )//arrayType
164 )//hasType
165 ,
166 // 3-d
167 hasType(
168 arrayType(
169 //hasElementType(
170 hasElementType(hasUnqualifiedDesugaredType(
171 arrayType(
172 hasElementType(
173 makeSignalArrayType(name))
174 ) //arrayType
175 )
176 ) //hasElementType
177 )//arrayType
178 )//hasType
179 ,
180 // Regular field declaration
181 hasType(
182 cxxRecordDecl(isDerivedFrom(hasName(name))).bind("desugar_"+name)
183 )
184 ,
185 hasType(pointerType(pointee(hasDeclaration(cxxRecordDecl(isDerivedFrom(hasName(name))).bind("desugar_"+name)))))
186 );
187 }
188
189 auto makeSignalMatcher(llvm::StringRef name) {
190 return fieldDecl(
191 signalMatcher(name.str())
192 ).bind("other_fields");
193 }
194
195 auto makeArrayTypeMatcher(const std::string &name) {
196 return recordType(hasDeclaration(cxxRecordDecl(hasName(name)).bind("desugar_"+name)));
197
198 }
208 auto portNameMatcher(const std::string &name) {
209 return
210 anyOf(
211 hasType(
212 arrayType(
213
214 anyOf(
215
216 // 1-d
217 hasElementType(hasUnqualifiedDesugaredType(
218 recordType(
219 hasDeclaration(
220 cxxRecordDecl(hasName(name)).bind("desugar_"+name)
221 )
222 )
223 )
224 )//hasElementType
225
226 ,
227
228 // 2-d
229 hasElementType(hasUnqualifiedDesugaredType(
230 arrayType(hasElementType(hasUnqualifiedDesugaredType(
232 ))
233 )//arrayType
234 )
235 )//hasElementType
236
237 ,
238 //3-d
239
240 hasElementType(hasUnqualifiedDesugaredType(
241 arrayType(hasElementType(hasUnqualifiedDesugaredType(
242 arrayType(hasElementType(hasUnqualifiedDesugaredType(
244 ))
245 )//arrayType
246 ))
247 )//arrayType
248 )
249 )//hasElementType
250
251
252 )//anyOf
253 )
254 ),
255 hasType(hasUnqualifiedDesugaredType(
256 anyOf(
257 recordType(
258 hasDeclaration(
259 cxxRecordDecl(hasName(name)).bind("desugar_"+name)
260 )
261 )
262 ,
263 pointerType(pointee(
264 hasDeclaration(
265 cxxRecordDecl(hasName(name)).bind("desugar_"+name)
266 )
267 ) // pointee
268 )
269 )
270
271 )
272 )
273 );
274 }
275
276 auto makePortHasNameMatcher(llvm::StringRef name) {
277 return fieldDecl(
278 portNameMatcher(name.str())
279 ).bind("other_fields");
280 }
281
288 auto makePortHasNamedDeclNameMatcher(llvm::StringRef name) {
289 return
290 fieldDecl(
291 anyOf(
292 hasType(arrayType(hasElementType(asString(name.str())))),
293 hasType(namedDecl(hasName(name.str())))
294 )
295 );
296 }
297
298 auto makeArraySubModule(llvm::StringRef name) {
299 return arrayType(
300 hasElementType(hasUnqualifiedDesugaredType(
301 recordType(
302 hasDeclaration(
303 cxxRecordDecl(isDerivedFrom(hasName(name.str()))).bind("submodule")
304 ) //hasDeclaration
305 )// recordType
306 ))
307 );
308 }
309
311 llvm::StringRef base_class{"::sc_core::sc_module"};
312
313 return
314 fieldDecl(
315 hasType(hasUnqualifiedDesugaredType(
316 anyOf(
317 // 1 instance
318 recordType(
319 hasDeclaration(
320 cxxRecordDecl(
321 isDerivedFrom(hasName("::sc_core::sc_module")),
322 unless(isDerivedFrom(matchesName("sc_event_queue")))
323 ).bind("submodule")
324 ) //hasDeclaration
325 ) //recordType
326
327 // 1D array
328 ,
329 makeArraySubModule(base_class)
330
331 // 2D array of modules
332 ,
333 arrayType(
334 hasElementType(hasUnqualifiedDesugaredType(
335 makeArraySubModule(base_class)
336 )//hasElementType
337 )
338 )//arrayType
339
340 // 3D array
341 ,
342 arrayType(
343 hasElementType(hasUnqualifiedDesugaredType(
344 arrayType(hasElementType(
345 makeArraySubModule(base_class)
346 )//hasElementType
347 ) // arrayType
348 ) //hasUnqualifiedDesugaredType
349 ) // hasElementType
350 )//arrayType
351
352 ) // anyOf
353
354 ) //hasUnqualifiedDesugaredType
355 ) //hasType
356 ).bind("submodule_fd"); // fieldDecl;
357
358 }
359 /* clang-format on */
360
361 template <typename NodeType>
362 auto checkMatch(const std::string &name,
363 const MatchFinder::MatchResult &result) {
364 return result.Nodes.getNodeAs<NodeType>(name);
365 }
366
368 // Input ports
369 for (const auto &i : found_ports) {
370 LLVM_DEBUG(llvm::dbgs() << "name: " << get<0>(i) << ", FieldDecl*: "
371 << get<1>(i)->getAsFieldDecl());
372 LLVM_DEBUG(
373 get<1>(i)->getTemplateType()->printTemplateArguments(llvm::dbgs()));
374 LLVM_DEBUG(llvm::dbgs() << "\n");
375 }
376 }
377
378 template <typename T>
379 auto parseTemplateType(const T *fd) {
380 clang::QualType qual_type{fd->getType()};
381 const clang::Type *type_ptr{qual_type.getTypePtr()};
382 auto template_ptr{new FindTemplateTypes()};
383 template_ptr->Enumerate(type_ptr);
384 LLVM_DEBUG(template_ptr->printTemplateArguments(llvm::dbgs()));
385 return template_ptr;
386 }
387
388 template <typename T>
389 void insert_port(MemberDeclType &port, T *decl, bool isFieldDecl = true) {
390 // port is a map entry [CXXRecordDecl* => vector<PortDecl*>]
391
392 std::string name{};
393 if (auto *fd = dyn_cast<clang::FieldDecl>(decl)) {
394 name = fd->getIdentifier()->getNameStart();
395
396 PortDecl *new_pd{new PortDecl(name, decl, parseTemplateType(fd))};
397
398 std::vector<llvm::APInt> sizes{ getConstantArraySizes(fd) };
399
400 if (sizes.size() > 0 ) {
401 new_pd->setArrayType();
402 for (auto const &array_size : sizes ) {
403 new_pd->addArraySize(array_size);
404 }
405 }
406
407 auto port_entry{std::make_tuple(name, new_pd)};
408 port.push_back(port_entry);
409
410 } else {
411
412 if (auto *vd = dyn_cast<clang::VarDecl>(decl)) {
413 name = vd->getIdentifier()->getNameStart();
414 PortDecl *new_pd{new PortDecl(name, decl, parseTemplateType(vd))};
415
416 auto field_type{vd->getType()};
418 auto array_type{dyn_cast<ConstantArrayType>(field_type)};
419 if (array_type) {
420 new_pd->setArrayType();
421 while (array_type != nullptr) {
422 llvm::APInt array_size{};
423 array_size = array_type->getSize();
424 LLVM_DEBUG(llvm::dbgs()
425 << "Size of array: " << array_size << "\n";);
426 array_type =
427 dyn_cast<ConstantArrayType>(array_type->getElementType());
428
429 new_pd->addArraySize(array_size);
430 }
431 }
432
433 auto port_entry{std::make_tuple(name, new_pd)};
434 port.push_back(port_entry);
435 }
436 }
437 }
438
439 void registerMatchers(MatchFinder &finder) {
440 /* clang-format off */
441
442 //
445 auto match_module_decls =
446 cxxRecordDecl(
447 //matchesName(top_module_decl_), // Specifies the top-level module name.
448 hasDefinition(), // There must be a definition.
449 unless( isImplicit() ), // Templates generate implicit structs - so ignore.
450 isDerivedFrom(
451 hasName("::sc_core::sc_module")
452 ),
453 unless(isDerivedFrom(matchesName("sc_event_queue")))
454 );
455
456
458 auto match_sc_ports = cxxRecordDecl(
459 match_module_decls,
460 forEach(
461 fieldDecl(
462 hasType(
463 cxxRecordDecl(isDerivedFrom(hasName("sc_port")))
464 )
465 ).bind("sc_port")
466 )
467 );
468
469 auto match_all_ports = cxxRecordDecl(
470 match_module_decls,
471 eachOf(
472 forEach(
474 forEach(
475 makePortHasNameMatcher("sc_in")),
476 forEach(
477 makePortHasNameMatcher("sc_out")),
478 forEach(
479 makePortHasNameMatcher("sc_inout")),
480 forEach(
481 makeSignalMatcher("sc_signal_inout_if")),
482 forEach(
483 makePortHasNameMatcher("sc_stream_in")),
484 forEach(
485 makePortHasNameMatcher("sc_rvd_in")),
486 forEach(
487 makePortHasNameMatcher("sc_rvd_out")),
488 forEach(
489 makePortHasNameMatcher("sc_stream_out"))
490 )
491 );
492 // Notice that the ports can also be arrays.
493
494 auto match_non_sc_types_fdecl =
495 cxxRecordDecl(
496 match_module_decls,
497 //unless(match_all_ports),
498 forEach(fieldDecl(
499 unless(portNameMatcher("sc_in_clk")),
500 unless(portNameMatcher("sc_in")),
501 unless(portNameMatcher("sc_out")),
502 unless(portNameMatcher("sc_inout")),
503 unless(portNameMatcher("sc_stream_in")),
504 unless(portNameMatcher("sc_stream_out")),
505 unless(portNameMatcher("sc_rvd_in")),
506 unless(portNameMatcher("sc_rvd_out")),
507 unless(signalMatcher("sc_signal_inout_if")),
508 unless(portNameMatcher("sc_rvd_in")),
509 unless(portNameMatcher("sc_rvd_out")),
510 unless(makeMemberIsSubModule())
511 ).bind("other_fvdecl")));
512
513 auto match_non_sc_types_vdecl = cxxRecordDecl(
514 forEach(
515 varDecl(
516 unless(portNameMatcher("sc_in_clk")),
517 unless(portNameMatcher("sc_in")),
518 unless(portNameMatcher("sc_out")),
519 unless(portNameMatcher("sc_inout")),
520 unless(portNameMatcher("sc_stream_in")),
521 unless(portNameMatcher("sc_stream_out")),
522 unless(portNameMatcher("sc_rvd_in")),
523 unless(portNameMatcher("sc_rvd_out")),
524 unless(signalMatcher("sc_signal_inout_if")),
525 unless(portNameMatcher("sc_rvd_in")),
526 unless(portNameMatcher("sc_rvd_out")),
527 unless(makeMemberIsSubModule())
528
529 ).bind("other_fvdecl")));
530
531 auto match_submodules = cxxRecordDecl(
532 forEach(
534 )
535 );
536 /* clang-format on */
537
538 // Add matchers to finder.
539 finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, match_all_ports) , this);
540 finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, match_non_sc_types_fdecl), this);
541 finder.addMatcher(traverse(TK_IgnoreUnlessSpelledInSource, match_non_sc_types_vdecl), this);
542 //finder.addMatcher(match_submodules, this);
543 // finder.addMatcher(match_sc_ports, this);
544 }
545
546 virtual void run(const MatchFinder::MatchResult &result) {
547 auto sc_in_field{checkMatch<clang::CXXRecordDecl>("desugar_sc_in", result)};
548 auto sc_out_field{
549 checkMatch<clang::CXXRecordDecl>("desugar_sc_out", result)};
550 auto sc_inout_field{
551 checkMatch<clang::CXXRecordDecl>("desugar_sc_inout", result)};
552 auto sc_signal_field{
553 checkMatch<clang::CXXRecordDecl>("desugar_sc_signal_inout_if", result)};
554 auto sc_stream_in_field{
555 checkMatch<clang::CXXRecordDecl>("desugar_sc_stream_in", result)};
556 auto sc_stream_out_field{
557 checkMatch<clang::CXXRecordDecl>("desugar_sc_stream_out", result)};
558 auto sc_rvd_in_field{
559 checkMatch<clang::CXXRecordDecl>("desugar_sc_rvd_in", result)};
560 auto sc_rvd_out_field{
561 checkMatch<clang::CXXRecordDecl>("desugar_sc_rvd_out", result)};
562 auto sc_port_field{
563 checkMatch<clang::CXXRecordDecl>("desugar_sc_port", result)};
564 auto other_fields{checkMatch<clang::Decl>("other_fields", result)};
565 auto other_fvdecl{checkMatch<clang::Decl>("other_fvdecl", result)};
566
568 // auto array_type{checkMatch<clang::ArrayType>("array_type", result)};
569
571 auto submodule_fd{checkMatch<clang::FieldDecl>("submodule_fd", result)};
572
573 if (submodule_fd) {
574 auto name{submodule_fd->getNameAsString()};
575 LLVM_DEBUG(llvm::dbgs() << "Found submodule: " << name << "\n");
576 insert_port(submodules_, submodule_fd);
577 }
578
579 if (sc_in_field && other_fields) {
580 if (auto *p_field{dyn_cast<clang::FieldDecl>(other_fields)}) {
581 auto fd = p_field;
582 auto port_name{fd->getIdentifier()->getNameStart()};
583 LLVM_DEBUG(llvm::dbgs() << " Found sc_in: " << port_name << "\n");
585 }
586 }
587
588 if (sc_out_field && other_fields) {
589 if (auto *p_field{dyn_cast<clang::FieldDecl>(other_fields)}) {
590 auto fd = p_field;
591 auto port_name{fd->getIdentifier()->getNameStart()};
592 LLVM_DEBUG(llvm::dbgs() << " Found sc_out: " << port_name << "\n");
593
595 }
596 }
597
598 if (sc_inout_field && other_fields) {
599 if (auto *p_field{dyn_cast<clang::FieldDecl>(other_fields)}) {
600 auto fd = p_field;
601 auto port_name{fd->getIdentifier()->getNameStart()};
602 LLVM_DEBUG(llvm::dbgs() << " Found sc_inout: " << port_name << "\n");
604 }
605 }
606
607 if (sc_signal_field && other_fields) {
608 if (auto *p_field{dyn_cast<clang::FieldDecl>(other_fields)}) {
609 auto fd = p_field;
610 auto signal_name{fd->getIdentifier()->getNameStart()};
611 llvm::dbgs() << " Found sc_signal: " << signal_name << "\n";
613 }
614 }
615
616 if (sc_stream_in_field && other_fields) {
617 if (auto *p_field{dyn_cast<clang::FieldDecl>(other_fields)}) {
618 auto fd = p_field;
619 auto field_name{fd->getIdentifier()->getNameStart()};
620 LLVM_DEBUG(llvm::dbgs()
621 << " Found sc_stream_in: " << field_name << "\n");
623 }
624 }
625
626 if (sc_stream_out_field && other_fields) {
627 if (auto *p_field{dyn_cast<clang::FieldDecl>(other_fields)}) {
628 auto fd = p_field;
629 auto field_name{fd->getIdentifier()->getNameStart()};
630 LLVM_DEBUG(llvm::dbgs()
631 << " Found sc_stream_out: " << field_name << "\n");
633 }
634 }
635
636 if (sc_rvd_in_field && other_fields) {
637 if (auto *p_field{dyn_cast<clang::FieldDecl>(other_fields)}) {
638 auto fd = p_field;
639 auto field_name{fd->getIdentifier()->getNameStart()};
640 LLVM_DEBUG(llvm::dbgs() << " Found sc_rvd_in: " << field_name << "\n");
642 }
643 }
644
645 if (sc_rvd_out_field && other_fields) {
646 if (auto *p_field{dyn_cast<clang::FieldDecl>(other_fields)}) {
647 auto fd = p_field;
648 auto field_name{fd->getIdentifier()->getNameStart()};
649 LLVM_DEBUG(llvm::dbgs() << " Found sc_rvd_out: " << field_name << "\n");
651 }
652 }
653
654 if (sc_port_field && other_fields) {
655 if (auto *p_field{dyn_cast<clang::FieldDecl>(other_fields)}) {
656 auto fd = p_field;
657 auto field_name{fd->getIdentifier()->getNameStart()};
658 LLVM_DEBUG(llvm::dbgs() << " Found sc_port : " << field_name << "\n");
660 }
661 }
662
663 auto is_ports{(sc_in_field) || sc_out_field || sc_inout_field ||
664 sc_signal_field || sc_stream_in_field || sc_stream_out_field};
665
667 if ((!is_ports)) {
668 // These will be either FieldDecl or VarDecl.
669 auto fd{other_fvdecl};
670 if (fd) {
671 LLVM_DEBUG(llvm::dbgs() << "Print out the other fd\n");
672
673 if (auto *p_field{dyn_cast<clang::FieldDecl>(fd)}) {
674 auto field_name{p_field->getIdentifier()->getNameStart()};
675 LLVM_DEBUG(llvm::dbgs()
676 << " Found field other_fields: " << field_name << "\n");
677
678 p_field->dump();
679 insert_port(other_fields_, p_field);
680
681 } else {
682 auto *p_var{dyn_cast<clang::VarDecl>(fd)};
683 auto field_name{p_var->getIdentifier()->getNameStart()};
684 LLVM_DEBUG(llvm::dbgs()
685 << " Found var other_fields: " << field_name << "\n");
687 }
688 }
689 }
690 }
691
705};
706}; // namespace sc_ast_matchers
707
708#endif
const MemberDeclType & getPorts() const
Returns the identified ports.
const MemberDeclType & getClockPorts() const
Definition PortMatcher.h:71
MemberDeclType outstream_ports_
Definition PortMatcher.h:61
const MemberDeclType & getOtherVars() const
Definition PortMatcher.h:87
PortMatcher()
Default constructor.
void printTemplateArguments(MemberDeclType &found_ports)
auto makeFieldMatcher(llvm::StringRef name)
AST matcher to detect field declarations.
const MemberDeclType & getSubmodules() const
Definition PortMatcher.h:95
const MemberDeclType & getInputStreamPorts() const
Definition PortMatcher.h:99
const MemberDeclType & getSignals() const
Definition PortMatcher.h:91
void registerMatchers(MatchFinder &finder)
MemberDeclType submodules_
Store the declaration of submodules.
Definition PortMatcher.h:65
auto checkMatch(const std::string &name, const MatchFinder::MatchResult &result)
void insert_port(MemberDeclType &port, T *decl, bool isFieldDecl=true)
const MemberDeclType & getInOutPorts() const
Definition PortMatcher.h:83
auto makePortHasNameMatcher(llvm::StringRef name)
MemberDeclType clock_ports_
Separate out the member declarations found within a SystemC module.
Definition PortMatcher.h:54
const MemberDeclType & getOutputStreamPorts() const
auto makePortHasNamedDeclNameMatcher(llvm::StringRef name)
auto signalMatcher(const std::string &name)
const MemberDeclType & getInputPorts() const
Definition PortMatcher.h:75
auto makeArraySubModule(llvm::StringRef name)
MemberDeclType instream_ports_
Definition PortMatcher.h:60
auto portNameMatcher(const std::string &name)
auto makeSignalArrayType(const std::string &name)
const MemberDeclType & getOutputPorts() const
Definition PortMatcher.h:79
MemberDeclType signal_fields_
Definition PortMatcher.h:59
auto makeSignalMatcher(llvm::StringRef name)
auto parseTemplateType(const T *fd)
virtual void run(const MatchFinder::MatchResult &result)
auto makeArrayTypeMatcher(const std::string &name)
std::vector< std::tuple< std::string, PortDecl * > > MemberDeclType
Definition PortMatcher.h:47
void Enumerate(const clang::Type *type)
ArraySizesType getConstantArraySizes(const clang::ValueDecl *fd)