systemc-clang 2.0.0
Parsing SystemC constructs
Loading...
Searching...
No Matches
HDLThread.cpp
Go to the documentation of this file.
1// clang-format off
2#include "HDLThread.h"
3#include "SplitCFGBlock.h"
4//clang-format on
5
7#undef DEBUG_TYPE
8#define DEBUG_TYPE "HDL"
9
18
19
20using namespace systemc_clang;
21
22namespace systemc_hdl {
23
25 clang::DiagnosticsEngine &diag_engine,
26 const ASTContext &ast_context, hdecl_name_map_t &mod_vname_map,
27 hfunc_name_map_t &allmethodecls, overridden_method_map_t &overridden_method_map, hNodep h_resetvarinfo )
28 : efc_(efc), h_top_{h_top}, diag_e{diag_engine}, ast_context_{ast_context},
29 mod_vname_map_{mod_vname_map}, allmethodecls_{allmethodecls}, overridden_method_map_{overridden_method_map},
30 h_resetvarinfo_{h_resetvarinfo}, scfg{const_cast<ASTContext &>(ast_context), efc->getEntryMethod()} {
31
32 LLVM_DEBUG(llvm::dbgs() << "Entering HDLThread constructor (thread body)\n");
33
34 CXXMethodDecl *emd = efc->getEntryMethod();
35
36 h_ret = NULL;
37 needwaitswitchcase = false;
38
39 string threadname = h_top->getname();
40 state_string ="state_"+ threadname+statestringsymbol;
42 waitctr_string = "wait_counter_"+ threadname+statestringsymbol;
44 waitnextstate_string = "wait_next_state_"+ threadname+statestringsymbol;
46
49
50 //xtbodyp = new HDLBody(diag_e, ast_context_, mod_vname_map_);
51 xtbodyp = new HDLBody(diag_e, ast_context_, thread_vname_map, allmethodecls_, overridden_method_map);
52 hNodep hthreadmainmethod = new hNode(h_top->getname(), hNode::hdlopsEnum::hMethod);
53 hthreadblocksp = new hNode(hNode::hdlopsEnum::hSwitchStmt); // body is switch, each path is case alternative
54 hthreadblocksp->append(new hNode(state_string, hNode::hdlopsEnum::hVarref));
55 hlocalvarsp = new hNode(hNode::hdlopsEnum::hPortsigvarlist); // placeholder to collect local vars
56
57 hNodep hthreadblockcstmt = new hNode(hNode::hdlopsEnum::hCStmt);
58 hthreadblocksp->append(hthreadblockcstmt);
59 // build SC CFG
60
61 //SplitCFG scfg{const_cast<ASTContext &>(ast_context_), emd};
63 LLVM_DEBUG(llvm::dbgs() << "Dumping scfg paths.\n");
64 LLVM_DEBUG(scfg.dump());
65 LLVM_DEBUG(scfg.dumpToDot());
66
67 const llvm::SmallVectorImpl<llvm::SmallVector<SplitCFG::SplitCFGPathPair>> &paths_found{ scfg.getPathsFound()};
68
69 numstates = paths_found.size();
70 int state_num;
71
72 for (state_num = 0; state_num < paths_found.size(); state_num++) {
73 SGVisited.clear();
74 // pathnodevisited keeps track of nodes already traversed in true and false paths.
75 // those were already done by ProcessSplitGraphGroup and should be skipped
76 pathnodevisited.clear();
77 hNodep h_switchcase = new hNode( hNode::hdlopsEnum::hSwitchCase);
78 h_switchcase->append(new hNode(std::to_string(state_num), hNode::hdlopsEnum::hLiteral));
79 ProcessSplitGraphGroup(paths_found[state_num], 0,
80 paths_found[state_num].size(),
81 state_num, h_switchcase);
82 hthreadblockcstmt->append(h_switchcase);
83
84 }
85
87 hNodep h_switchcase = new hNode( hNode::hdlopsEnum::hSwitchCase);
88 h_switchcase->append(new hNode(std::to_string(numstates), hNode::hdlopsEnum::hLiteral));
89 GenerateWaitCntUpdate(h_switchcase);
90 hthreadblockcstmt->append(h_switchcase);
91 }
92
93 // for all variables (and signals) referenced in thread,
94 // we need two copies to hold the variables' value across clock cycles.
95 // these variables may be local or global
96 hNodep h_shadowvarsp = new hNode(hNode::hdlopsEnum::hPortsigvarlist); // collect referenced variables
97
98 for (auto const &var: thread_vname_map) {
99 if (var.second.referenced) {
100 // create a copy, same child_list
101 hNodep hs = new hNode(var.second.h_vardeclp->getname(), var.second.h_vardeclp->getopc());
102 hs->child_list = var.second.h_vardeclp->child_list;
103 h_shadowvarsp->append(hs);
104 if (var.second.newn.find(hnode::gvar_prefix) != string::npos) // global object
105 string gname = mod_vname_map.find_entry_newn(var.first, true); // set referenced bit in global name map
106 }
107 }
108
109 //std::unique_ptr< CFG > threadcfg = clang::CFG::buildCFG(emd, emd->getBody(), &(emd->getASTContext()), clang::CFG::BuildOptions());
110 //clang::LangOptions LO = ast_context.getLangOpts();
111 //threadcfg->dump(LO, false);
112 // HDLBody instance init
113 // for (auto const& pt: paths_found) {
114 // for (auto const& block : pt) {
115 // ProcessBB(*(block->getCFGBlock()));
116 // }
117 // }
118
119 // top of main method
120 hthreadmainmethod->append(GenerateBinop("=", nextstate_string, state_string, false));
121 hthreadmainmethod->append(GenerateBinop("=", nextwaitctr_string, waitctr_string, false));
122 hthreadmainmethod->append(GenerateBinop("=", savewaitnextstate_string, waitnextstate_string, false));
123 for (hNodep onelocalvar : h_shadowvarsp->child_list) {
124 hthreadmainmethod->append(GenerateBinop("=", onelocalvar->getname(), shadowstring+onelocalvar->getname()));
125 }
126 hthreadmainmethod->append(new hNode(threadname+"_func", hNode::hdlopsEnum::hMethodCall));
127 //hthreadmainmethod->append(hthreadblocksp);
128
129 // generate hnode tree for a function:
130 // <function> <ret type none> <cstmt containing switch stmt>
131
132 hNodep hfunctop = new hNode(threadname+"_func", hNode::hdlopsEnum::hFunction);
133 hfunctop->append(new hNode(hNode::hdlopsEnum::hFunctionRetType)); // placeholder: no return value
134 hNodep hcstmttmp = new hNode(hNode::hdlopsEnum::hCStmt);
135 hcstmttmp->append(hthreadblocksp);
136 hfunctop->append(hcstmttmp);
137 //hfunctop->append(hthreadblocksp);
138 //h_top->append(hthreadblocksp);
139 h_top->append(hfunctop);
140
141 // generate the local variables;
148 // generate the state update method
149 hNodep hstatemethod = new hNode(threadname+"_state_update", hNode::hdlopsEnum::hMethod);
150 GenerateStateUpdate(hstatemethod, h_shadowvarsp);
151 h_top->append(hstatemethod);
152
153 h_top->append(hthreadmainmethod);
154
155 // remove globals from shadowvars
156 h_shadowvarsp->child_list.erase(
157 std::remove_if( h_shadowvarsp->child_list.begin(),
158 h_shadowvarsp->child_list.end(), [] (hNodep x) {
159 return (x->getname().find(hnode::gvar_prefix) != string::npos);}),
160 h_shadowvarsp->child_list.end() );
161
162 // fix up names of local var shadows promoted
163 for (hNodep hchild: h_shadowvarsp->child_list) {
164 hchild->set(shadowstring+hchild->getname());
165 }
166
167 if (h_shadowvarsp->size()>0) {
168 hlocalvarsp->child_list.insert(std::end(hlocalvarsp->child_list),
169 std::begin(h_shadowvarsp->child_list),
170 std::end(h_shadowvarsp->child_list));
171 }
172 // add thread local variables to module level list
173
174 if (hlocalvarsp->size()!=0) h_portsigvarlist->child_list.insert(std::end(h_portsigvarlist->child_list),
175 std::begin(hlocalvarsp->child_list),
176 std::end(hlocalvarsp->child_list));
177 //h_top->append(hthreadblocksp);
178
179 }
180
182 LLVM_DEBUG(llvm::dbgs() << "[[ Destructor HDLThread ]]\n");
183 }
184
185 bool HDLThread::isContinueorBreak(const Stmt *S) {
186 if (isa<BreakStmt>(S)) return true;
187 if (isa<ContinueStmt>(S)) return true;
188 return false;
189 }
190
192 return ((hp->child_list.size() >=1) and ((hp->child_list.back())->getopc() == hNode::hdlopsEnum::hWait));
193 }
194
195 void HDLThread::CheckVardecls(hNodep &hp, string &blockid) {
196 int varcnt = 0;
197 for (auto oneop : hp->child_list) {
198 if ((oneop != NULL) && ((oneop->getopc() == hNode::hdlopsEnum::hVardecl) || (oneop->getopc() == hNode::hdlopsEnum::hSigdecl))) {
199 LLVM_DEBUG(llvm::dbgs() << "Detected vardecl for SG Block ID " << blockid << "\n");
200 if (SGVisited[blockid] == 1) { hlocalvarsp->append(oneop);
201 }
202 else {
203 LLVM_DEBUG(llvm::dbgs() << "SGVisited for blockid " << SGVisited[blockid]
204 << " " << blockid << "\n");
205 }
206 varcnt += 1;
207 }
208 else break; // all vardecls are first in the list of ops
209 }
210 if (varcnt >=1) {
211 hp->child_list.erase(hp->child_list.begin(), hp->child_list.begin()+varcnt);
212 if (SGVisited[blockid] == 1) {
214 }
215 }
216 }
217
218 void HDLThread::ProcessDeclStmt(const DeclStmt *declstmt, hNodep htmp) {
223
224 // adapted from ProcessVarDecl in HDLBody.cpp
225 for (auto *DI : declstmt->decls()) {
226 if (DI) {
227 auto *vardecl = dyn_cast<VarDecl>(DI);
228 if (!vardecl) continue;
229 if ( Expr *declinit = vardecl->getInit()) {
230 Stmt * cdeclinit = declinit;
231 // need to generated initializer code
232 //xtbodyp->Run(const_cast<Stmt *>((const Stmt *)declinit), hinitcode, rthread);
233 hNodep varinitp = new hNode(hNode::hdlopsEnum::hVarAssign);
234 varinitp->append(new hNode(thread_vname_map.find_entry_newn(vardecl, true),
235 hNode::hdlopsEnum::hVarref)); // set referenced bit
236 xtbodyp->Run(cdeclinit, varinitp, rthread);
237 htmp->append(varinitp);
238
239 }
240 }
241 }
242 }
243
244 void HDLThread::MarkStatements(const Stmt *S, llvm::SmallDenseMap<const Stmt*, bool> &Map) {
245 if (S != NULL) {
246 Map[S] = true;
247 for (const Stmt *K : S->children())
248 MarkStatements(K, Map);
249 }
250 }
251
252 // this version is no longer being used
253 void HDLThread::FindStatements(const CFGBlock &B, std::vector<const Stmt *> &SS) {
254 llvm::SmallDenseMap<const Stmt*, bool> Map;
255
256 // Mark subexpressions of each element in the block.
257 for (auto I = B.begin(); I != B.end(); ++I) {
258 CFGElement E = *I;
259 if (auto SE = E.getAs<CFGStmt>()) {
260 const Stmt *S = SE->getStmt();
261 for (const Stmt *K : S->children())
262 MarkStatements(K, Map);
263 }
264 }
265 // mark subexpressions coming from terminator statement
266 if (B.getTerminator().isValid()) {
267 const Stmt *S = B.getTerminatorStmt();
268 for (const Stmt *K : S->children())
269 MarkStatements(K, Map);
270 }
271 // Any expressions not in Map are top level statements.
272 for (auto I = B.begin(); I != B.end(); ++I) {
273 CFGElement E = *I;
274 if (auto SE = E.getAs<CFGStmt>()) {
275 const Stmt *S = SE->getStmt();
276 if (Map.find(S) == Map.end()) {
277 SS.push_back(S);
278 }
279 }
280 }
281 }
282
283 void HDLThread::FindStatements(const SplitCFGBlock *B, std::vector<const Stmt *> &SS) {
284 llvm::SmallDenseMap<const Stmt*, bool> Map;
285
286 // Mark subexpressions of each element in the block.
287 for (auto I : B->getElements()) {
288 CFGElement E = *I;
289 if (auto SE = E.getAs<CFGStmt>()) {
290 const Stmt *S = SE->getStmt();
291 for (const Stmt *K : S->children())
292 MarkStatements(K, Map);
293 }
294 }
295 // // mark subexpressions coming from terminator statement
296 if ((B->getCFGBlock())->getTerminator().isValid()) {
297 const Stmt *S = (B->getCFGBlock())->getTerminatorStmt();
298 for (const Stmt *K : S->children()) {
299 MarkStatements(K, Map);
300 }
301 //if (auto S1 = dyn_cast<WhileStmt>(S)
302 // if (Map.find(S) == Map.end()) {
303 // SS.push_back(S);
304 // }
305 LLVM_DEBUG(llvm::dbgs() << "Stmt contains terminator\n");
306 //LLVM_DEBUG(S->dump(llvm::dbgs(), ast_context_));
307 }
308
309 // Any expressions not in Map are top level statements.
310 for (auto I : B->getElements()) {
311 CFGElement E = *I;
312 if (auto SE = E.getAs<CFGStmt>()) {
313 const Stmt *S = SE->getStmt();
314 if (Map.find(S) == Map.end()) {
315 SS.push_back(S);
316 }
317 }
318 }
319 }
320
321 int HDLThread::GetFalseLength(const SplitCFG::SplitCFGPath &pt, int cond_node_ix, int state_num) {
322 auto path_info_{scfg.getAllPathInfo()};
323 auto sblock{pt[cond_node_ix].first};
324 auto supp_info{pt[cond_node_ix].second};
325 auto found_it{path_info_[state_num].find(supp_info.split_block_)};
326 int flen = 0;
327 LLVM_DEBUG(llvm::dbgs() << "Getting false path length of ");
328 LLVM_DEBUG(llvm::dbgs() << "(" << supp_info.path_idx_ << "," << sblock->getBlockID()
329 << "," << supp_info.false_idx_);
330 if (found_it != path_info_[state_num].end()) {
331 flen = found_it->second.getFalsePath().size();
332 }
333 LLVM_DEBUG(llvm::dbgs() << " |" << flen << "|");
334 LLVM_DEBUG(llvm::dbgs() << ")\n");
335 return flen;
336 }
337
338
340 // SplitCFGPath is llvm::SmallVector<std::pair<const SplitCFGBlock*, SplitCFGPathInfo>>
341 int startix, int num_ele,
342 int state_num, hNodep h_switchcase)
343 {
344
345 LLVM_DEBUG(llvm::dbgs() << "Split Graph Group startix, num_ele, state_num are " << startix << " " << num_ele << " " << state_num << "\n");
346
347 int pvix = startix;
348 while ( pvix<startix+num_ele) {
349 if (pathnodevisited.find(pvix) == pathnodevisited.end()) { //haven't visited
350 pathnodevisited.insert(pvix);
351 ProcessSplitGraphBlock(pt, pvix, state_num, h_switchcase);
352 pvix++;
353 }
354 else pvix++;
355 }
356 }
357
358 // SplitCFGPath = llvm::SmallVector<SplitCFGPathPair>;
359 // SplitCFGPathPair = std::pair<const SplitCFGBlock *, SupplementaryInfo>;
361 int thisix,
362 int state_num, hNodep h_switchcase)
363 {
364 const SplitCFGBlock *sgb{pt[thisix].first};
365 bool iswait = false;
366 if (sgb != NULL) {
367 string blkid = "S" + std::to_string(state_num) + "_" + std::to_string(sgb->getBlockID());
368
369 if (SGVisited.find(blkid) == SGVisited.end()) {
370 SGVisited[blkid] = 1;
371 }
372 else {
373 SGVisited[blkid] += 1;
374 }
375 //else return; // already visited this block
376
377 LLVM_DEBUG(llvm::dbgs() << "Split Graph num ele, blockid are " << sgb->getNumOfElements() << " " << blkid << "\n");
378 if ((sgb->getCFGBlock())->getTerminator().isValid() && sgb->hasWait()) {
379 LLVM_DEBUG(llvm::dbgs() << "found valid terminator with hasWait(), num ele in block is " << sgb->getNumOfElements() << "\n");
380 }
381 if ((sgb->getCFGBlock())->getTerminator().isValid() && !sgb->hasWait()){ // artifact of splitting graph is that wait retains terminator of cfg block
382 if (isContinueorBreak(sgb->getCFGBlock()->getTerminatorStmt()) && (sgb->getNumOfElements() ==0)) {
383 LLVM_DEBUG(llvm::dbgs() << "Terminator for block is singleton continue or break\n");
384 //if (h_switchcase->child_list.size()>0) h_switchcase->append(new hNode(hNode::hdlopsEnum::hReturnStmt));
385 return;
386 }
387
388 const Stmt * S = sgb->getCFGBlock()->getTerminatorStmt();
389 hNodep hcondstmt = new hNode(hNode::hdlopsEnum::hIfStmt);
390 if (isContinueorBreak(sgb->getCFGBlock()->getTerminatorStmt())) {
391 // continue or break as part of a block
392 hcondstmt->set(hNode::hdlopsEnum::hCStmt);
393 }
394
395 if (const WhileStmt *S1 = dyn_cast<WhileStmt> (S)) {
396 LLVM_DEBUG(llvm::dbgs() << "Terminator for block " <<blkid << " is a while stmt\n");
397 xtbodyp->Run((Stmt *)S1->getCond(), hcondstmt, rthread);
398 }
399 else if (const DoStmt *S1 = dyn_cast<DoStmt> (S)) {
400 LLVM_DEBUG(llvm::dbgs() << "Terminator for block " << blkid << " is a do stmt\n");
401 xtbodyp->Run((Stmt *)S1->getCond(), hcondstmt, rthread);
402 }
403 else if (const ForStmt *S1 = dyn_cast<ForStmt> (S)) {
404 LLVM_DEBUG(llvm::dbgs() << "Terminator for block " << blkid << " is a for stmt\n");
405 // if (!sgb->hasTerminatorWait()) {
406 // LLVM_DEBUG(llvm::dbgs() << "Terminator for block " << blkid << " doesn't have a wait()\n");
407 // LLVM_DEBUG(S1->dump(llvm::dbgs(), ast_context_));
408 // xtbodyp->Run((Stmt *)S1, h_switchcase, rmethod);
409 // for (int i = thisix+1; i < pt[thisix].second.getFalseId(); i++) {
410 // // need to mark all the true branch nodes in path vector as visited.
411 // updatepnvisited(i);
412 // }
413 // return;
414 // }
415 xtbodyp->Run((Stmt *)S1->getCond(), hcondstmt, rthread);
416 }
417 else if (const IfStmt *S1 = dyn_cast<IfStmt> (S)) {
418 LLVM_DEBUG(llvm::dbgs() << "Terminator for block " << blkid << " is an if stmt\n");
419 xtbodyp->Run((Stmt *)S1->getCond(), hcondstmt, rthread);
420 }
421 else if (const ConditionalOperator *S1 = dyn_cast<ConditionalOperator>(S)) {
422 LLVM_DEBUG(llvm::dbgs() << "Terminator for block " << blkid << " is conditional operator, skipping\n");
423 // below code doesn't work due to skipping too many nodes in true and false paths
424 // int flsix = pt[thisix].second.getFalseId();
425 // for (int i = thisix+1; i <flsix; i++) {
426 // // need to mark all the true branch nodes in path vector as visited.
427 // updatepnvisited(i);
428 // }
429 // for (int i =flsix; i < flsix+GetFalseLength(pt, thisix); i++) {
430 // // need to mark all the false branch nodes in path vector as visited.
431 // updatepnvisited(i);
432 // }
433 return;
434 }
435 else {
436 LLVM_DEBUG(llvm::dbgs() << "Terminator for block " << blkid << " not handled, is as follows\n");
437 LLVM_DEBUG(sgb->getCFGBlock()->getTerminatorStmt()->dump(llvm::dbgs(), ast_context_));
438 }
439
440 // process true branch
441 hNodep if1 = new hNode(hNode::hdlopsEnum::hCStmt);
442 hNodep if2 = NULL;
443 int flseix = pt[thisix].second.getFalseId();
444 ProcessSplitGraphGroup(pt, thisix+1, flseix - (thisix+1), state_num, if1);
445 //ProcessSplitGraphGroup(pt, thisix+1, flseix_vec[thisix].first - (thisix+1),
446 //state_num,if1);
447 if (if1->size() > 0) hcondstmt->append(if1);
448 if (flseix != 0) {// has false branch
449 if2 = new hNode(hNode::hdlopsEnum::hCStmt);
450 ProcessSplitGraphGroup(pt, flseix, GetFalseLength(pt, thisix, state_num),
451 state_num, if2);
452 }
453
454 if (if2!=NULL && if2->size() > 0) {
455 if (if1->size()==0) {
456 if1->set(hNode::hdlopsEnum::hNoop);
457 hcondstmt->append(if1);
458 }
459 hcondstmt->append(if2);
460 }
461 if (hcondstmt->size() >0) h_switchcase->append(hcondstmt);
462 return;
463 } // end if this was a terminator block
464
465
466 if (sgb->getNumOfElements() > 0) {
467
468 // from http://clang-developers.42468.n3.nabble.com/Visiting-statements-of-a-CFG-one-time-td4069440.html#a4069447
469 // had to add recursive traversal of AST node children
470 std::vector<const Stmt *> SS;
471 FindStatements(sgb, SS);
472 hNodep htmp = new hNode(h_top_->getname(), hNode::hdlopsEnum::hNoop);
473 //for (auto E : sgb->getElements()) {
474 //if (auto SE = E->getAs<CFGStmt>()) {
475 for (auto S : SS) {
476 //const Stmt *S = SE->getStmt();
477 if (sgb->hasWait()) iswait = true;
478 LLVM_DEBUG(llvm::dbgs() << "Split Graph Stmt follows\n");
479 LLVM_DEBUG(S->dump(llvm::dbgs(), ast_context_));
480
481 htmp->child_list.clear();
482
483 // Check if this CFG block has already been generated
484 // if so, skip the var decls. they were done on the
485 // first instantiation
486 // However, still need to generate code for their initializers
487 const DeclStmt *declstmt = dyn_cast<DeclStmt>(S);
488 if ((declstmt!=NULL) && (SGVisited[blkid]>1))
489 ProcessDeclStmt(declstmt, htmp);
490 else xtbodyp->Run(const_cast<Stmt *>(S), htmp, rthread); // not declstmt
491
492 LLVM_DEBUG(llvm::dbgs() << "after Run, htmp follows\n");
493 //htmp->dumphcode();
494 LLVM_DEBUG(htmp->print(llvm::dbgs()));
495 CheckVardecls(htmp,blkid);
496 if (IsWaitStmt(htmp)) {
497 ProcessHWait(htmp, sgb->getNextState());
498 //htmp->child_list.back()->set(std::to_string(sgb->getNextState()));
499 }
500 if (htmp->child_list.size() >0)
501 h_switchcase->child_list.insert(h_switchcase->child_list.end(), htmp->child_list.begin(), htmp->child_list.end());
502
503 //htmp->child_list.clear();
504
506 }
507 //hthreadblocksp->append(h_switchcase);
508 }
509
510
511 // if (!iswait) {
512 // for (auto succ : sgb->getSuccessors()) {
513 // LLVM_DEBUG(llvm::dbgs() << "element successor path, block id is " << succ->getBlockID() << "\n");
514 // ProcessSplitGraphBlock(succ, state_num, h_switchcase, scfg);
515 // }
516 // }
517 }
518 }
519
520 void HDLThread::ProcessHWait(hNodep htmp, int nxtstate) {
521 hNodep hw = htmp->child_list.back(); // the wait instruction
522 if (hw->child_list.size() == 0) {
523 hw->set(hNode::hdlopsEnum::hBinop, "=");
524 hw->append(new hNode(nextstate_string, hNode::hdlopsEnum::hVarref));
525 hw->append(new hNode(std::to_string(nxtstate), hNode::hdlopsEnum::hLiteral));
526 }
527 else {
528 needwaitswitchcase = true;
529 // generate waitcounter = wait arg; nextwaitstate = nxtstate; nextstate = waitstate (which is numstates)
530 hNodep hnewinstr = hw->child_list.back();
531 string waitarg = hnewinstr->getname();
532 // wait counter = wait arg
533 hw->set( hNode::hdlopsEnum::hBinop, "=");
534 hnewinstr->set(hNode::hdlopsEnum::hVarref, nextwaitctr_string);
535 hw->append(new hNode(waitarg, hNode::hdlopsEnum::hLiteral));
536
537 // nextwaitstate = nextstate
538 htmp->append(GenerateBinop("=", savewaitnextstate_string, std::to_string(nxtstate), true));
539
540 // nextstate = waitstate
541 htmp->append(GenerateBinop("=", nextstate_string, std::to_string(numstates)));
542 }
543 htmp->append(new hNode(hNode::hdlopsEnum::hReturnStmt));
544 }
545
547 // wait ctr -=1
548 hNodep hw = new hNode("--", hNode::hdlopsEnum::hPostfix);
549 hw->append(new hNode(nextwaitctr_string, hNode::hdlopsEnum::hVarref));
550 h_switchcase->append(hw);
551 // if (wait ctr == 0) nextstate = nextwaitstate
552 hw = new hNode(hNode::hdlopsEnum::hIfStmt);
553 hw->append(GenerateBinop("==", waitctr_string, "0"));
554 // then clause
556 h_switchcase->append(hw);
557
558 }
559
560 void HDLThread::GenerateStateUpdate(hNodep hstatemethod, hNodep hshadowvarsp){
561 const string comb_assign = "@=";
562 hNodep hifblock = new hNode(hNode::hdlopsEnum::hIfStmt);
563 // expecting
564 // hSensvar ASYNC [
565 // hVarref arst NOLIST
566 // hLiteral 0 NOLIST
567 // ]
568
569 if ((h_resetvarinfo_ != NULL) && (h_resetvarinfo_->child_list.size() == 2)) {
570 hifblock->append(GenerateBinop("==", h_resetvarinfo_->child_list[0]->getname(),
571 h_resetvarinfo_->child_list[1]->getname()));
572 }
573 else hifblock->append(GenerateBinop("==", efc_->getResetSignal().first, efc_->getResetEdge().first, false));
574
575 // then part: reset state transition variables
576 hNodep hcstmt = new hNode(hNode::hdlopsEnum::hCStmt);
577 hcstmt->append(GenerateBinop(comb_assign, state_string, "0"));
578 hcstmt->append(GenerateBinop(comb_assign, waitnextstate_string, "0"));
579 hcstmt->append(GenerateBinop(comb_assign, waitctr_string, "0"));
580
581 // now do the referenced variables
582 for (hNodep onelocalvar : hshadowvarsp->child_list) {
583 //hcstmt->append(GenerateBinop(comb_assign, onelocalvar->getname(), "0")); // assume all coercible to int; need prior check
584 hcstmt->append(GenerateBinop(comb_assign, shadowstring+onelocalvar->getname(), "0")); // assume all coercible to int; need prior check
585
586 }
587
588 hifblock->append(hcstmt);
589
590 // else part: set state transition variables
591 hcstmt = new hNode(hNode::hdlopsEnum::hCStmt);
592 hcstmt->append(GenerateBinop(comb_assign, state_string, nextstate_string, false));
593 //hcstmt->append(GenerateBinop(comb_assign, waitnextstate_string, nextwaitnextstate_string, false));
594 hcstmt->append(GenerateBinop(comb_assign, waitctr_string, nextwaitctr_string, false));
596
597 // now do the referenced variables
598 for (hNodep onelocalvar : hshadowvarsp->child_list) {
599 string s = onelocalvar->getname();
600 hcstmt->append(GenerateBinop(comb_assign,shadowstring+s, s, false));
601 }
602 hifblock->append(hcstmt);
603 hstatemethod->append(hifblock);
604 }
605
606 void HDLThread::GenerateStateVar(string sname) {
607 // add var decls for a state variable
608
609 hNodep hsigp = new hNode(sname, hNode::hdlopsEnum::hVardecl);
610 hNodep htypeinfo = new hNode(hNode::hdlopsEnum::hTypeinfo);
611 htypeinfo->append(new hNode("int", hNode::hdlopsEnum::hType));
612 hsigp->append(htypeinfo);
613 hlocalvarsp->append(hsigp);
614 }
615
616 hNodep HDLThread::GenerateBinop( string opname, string lhs, string rhs, bool rhs_is_literal) {
617 hNodep newbinop = new hNode(opname, hNode::hdlopsEnum::hBinop);
618 newbinop->append(new hNode(lhs, hNode::hdlopsEnum::hVarref));
619 newbinop->append(new hNode(rhs, rhs_is_literal ? hNode::hdlopsEnum::hLiteral :hNode::hdlopsEnum::hVarref));
620 return newbinop;
621 }
622
623 // Code below this line is obsolete
624 // BFS traversal so all local decls are seen before being referenced
625 #if 0
626 void HDLThread::AddThreadMethod(const CFGBlock &BI) {
627 std::vector<const CFGBlock *> succlist, nextsucclist;
628 ProcessBB(BI);
629 //CFGVisited[BI.getBlockID()]+=1;
630 for (const auto &succ : BI.succs() ) { // gather successors
631 const CFGBlock *SuccBlk = succ.getReachableBlock();
632 if (SuccBlk!=NULL) succlist.push_back(SuccBlk);
633 }
634 bool changed;
635 do {
636 changed = false;
637 for (const CFGBlock *si: succlist) { //process BB of successors at this level
638 if (CFGVisited.find(si->getBlockID()) == CFGVisited.end()) {
639 CFGVisited[si->getBlockID()]+= 1;
640 LLVM_DEBUG(llvm::dbgs() << "Visiting Block " << si->getBlockID() << "\n");
641 ProcessBB(*si);
642 changed = true;
643 for (auto sii: si->succs()) {
644 const CFGBlock *SuccBlk = sii.getReachableBlock();
645 if (SuccBlk!=NULL) nextsucclist.push_back(SuccBlk); // gather successors at next level
646 }
647 }
648 }
649 succlist = nextsucclist;
650 }
651 while (changed);
652 }
653
654 void HDLThread::ProcessBB(const CFGBlock &BI) {
655 string blkid = std::to_string(BI.getBlockID());
656 if (BI.size() > 0) {
657 hNodep h_body = new hNode("B"+blkid, hNode::hdlopsEnum::hMethod);
658 // from http://clang-developers.42468.n3.nabble.com/Visiting-statements-of-a-CFG-one-time-td4069440.html#a4069447
659 // had to add recursive traversal of AST node children
660 std::vector<const Stmt *> SS;
661 FindStatements(BI, SS);
662
663 hNodep htmp = new hNode(h_top_->getname(), hNode::hdlopsEnum::hNoop); // put the statement here temporarily
664 for (auto stmt: SS) {
665 LLVM_DEBUG(llvm::dbgs() << "Stmt follows\n");
666 LLVM_DEBUG(stmt->dump(llvm::dbgs(), ast_context_));
667 //generate hcode for this statement,
668 //HDLBody xmethod(const_cast<Stmt *>(stmt), h_body, diag_e, ast_context_, mod_vname_map_, false);
669 xtbodyp->Run(const_cast<Stmt *>(stmt), htmp, rthread);
670 CheckVardecls(htmp, BI.getBlockID());
671 if (htmp->child_list.size() >0)
672 h_body->child_list.insert(h_body->child_list.end(), htmp->child_list.begin(), htmp->child_list.end());
673
674 htmp->child_list.clear();
675
677 }
678 hthreadblocksp->append(h_body);
679 }
680 }
681#endif
682
683}
string getname()
Definition hNode.h:169
void set(hdlopsEnum h, string s="")
Definition hNode.h:148
std::vector< hNodep > child_list
Definition hNode.h:109
void append(hNodep hnew)
Definition hNode.h:157
int size()
Definition hNode.h:161
void print(llvm::raw_ostream &modelout=llvm::outs(), unsigned int indnt=2)
Definition hNode.h:188
void insertall(hfunc_name_map_t newmap)
Definition hNode.h:613
void reset_referenced()
Definition hNode.h:567
string find_entry_newn(T declp, bool set_ref=false)
Definition hNode.h:552
void insertall(newname_map_t< T > newmap)
Definition hNode.h:594
const std::pair< std::string, const clang::Expr * > getResetSignal() const
const std::pair< std::string, const clang::Expr * > getResetEdge() const
const VectorCFGElementPtrImpl & getElements() const
Returns the elements in this block.
const clang::CFGBlock * getCFGBlock() const
Returns the pointer to the original CFGBlock from which the SplitCFGBlock was created.
void dump() const
Dump member functions.
void generate_paths()
Generates the paths between wait statements.
Definition SplitCFG.cpp:836
const llvm::SmallVectorImpl< llvm::SmallVector< SplitCFGPathPair > > & getPathsFound()
Returns the paths that were found in the SCCFG.
llvm::SmallVector< SplitCFGPathPair > SplitCFGPath
Definition SplitCFG.h:95
const llvm::SmallVector< std::unordered_map< const SplitCFGBlock *, SplitCFGPathInfo > > & getAllPathInfo() const
hdecl_name_map_t vname_map
Definition HDLBody.h:88
hfunc_name_map_t methodecls
Definition HDLBody.h:84
void Run(Stmt *stmt, hNodep &h_top, HDLBodyMode runmode, HDLType *HDLt_userclassesp=NULL)
Definition HDLBody.cpp:75
void ProcessSplitGraphGroup(const SplitCFG::SplitCFGPath pt, int startix, int num_ele, int state_num, hNodep h_switchcase)
void GenerateStateVar(string sname)
int GetFalseLength(const SplitCFG::SplitCFGPath &pt, int cond_node_ix, int state_num)
void GenerateStateUpdate(hNodep hstatemethod, hNodep hlocalvarsp)
string savewaitnextstate_string
Definition HDLThread.h:59
bool isContinueorBreak(const Stmt *S)
clang::DiagnosticsEngine & diag_e
Definition HDLThread.h:34
void CheckVardecls(hNodep &hp, string &cfgblockid)
const clang::ASTContext & ast_context_
Definition HDLThread.h:110
hdecl_name_map_t & mod_vname_map_
Definition HDLThread.h:47
const string statestringsymbol
Definition HDLThread.h:65
hfunc_name_map_t allmethodecls_
Definition HDLThread.h:52
void ProcessHWait(hNodep htmp, int nxtstate)
const string shadowstring
Definition HDLThread.h:64
void ProcessSplitGraphBlock(const SplitCFG::SplitCFGPath &pt, int thisix, int state_num, hNodep h_switchcase)
hfunc_name_map_t methodecls
Definition HDLThread.h:32
void AddThreadMethod(const CFGBlock &BI)
std::unordered_map< std::string, int > SGVisited
Definition HDLThread.h:70
std::unordered_set< int > pathnodevisited
Definition HDLThread.h:72
void MarkStatements(const Stmt *S, llvm::SmallDenseMap< const Stmt *, bool > &Map)
hNodep GenerateBinop(string opname, string lhs, string rhs, bool rhs_is_literal=true)
void ProcessBB(const CFGBlock &BI)
string NameNext(string &s)
Definition HDLThread.h:67
void GenerateWaitCntUpdate(hNodep h_switchcase)
bool IsWaitStmt(hNodep hp)
HDLThread(EntryFunctionContainer *efc, hNodep &h_top, hNodep &h_portsigvarlist, clang::DiagnosticsEngine &diag_engine, const ASTContext &ast_context, hdecl_name_map_t &mod_vname_map, hfunc_name_map_t &allmethods, overridden_method_map_t &overridden_method_map, hNodep h_resetvarinfo)
Definition HDLThread.cpp:24
void FindStatements(const CFGBlock &B, std::vector< const Stmt * > &SS)
EntryFunctionContainer * efc_
Definition HDLThread.h:40
hdecl_name_map_t thread_vname_map
Definition HDLThread.h:45
void ProcessDeclStmt(const DeclStmt *declstmt, hNodep htmp)
std::unordered_map< const CXXMethodDecl *, const CXXMethodDecl * > overridden_method_map_t
Definition hNode.h:628