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