#include "leak_detector.h" #include "ReadWriteAnalyzer.h" using namespace std; void ReadWriteAnalyzer::init(SgFile* forFile) { auto save = current_file->filename(); modified_pars = ReadWriteAnalyzer::load_modified_pars(funcInfo); for (int j = 0; j < forFile->numberOfFunctions(); ++j) { SgStatement* func_hdr = forFile->functions(j); SgStatement* last = func_hdr->lastNodeOfStmt(); for (SgStatement* runner = func_hdr->lexNext(); runner != last; runner = runner->lexNext()) { // TODO: is it ok to skip all of them? if (!isSgExecutableStatement(runner) || isDVM_stat(runner) || isSPF_stat(runner)) continue; if (runner->variant() == CONTAINS_STMT) break; VarUsages usages = findUsagesInStatement(runner); auto it = usages_by_statement.find(runner); if (it != usages_by_statement.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); usages_by_statement[runner] = usages; } } initialized.insert(forFile->filename()); if (SgFile::switchToFile(save) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } VarUsages ReadWriteAnalyzer::findUsagesInStatement(SgStatement* st) const { // *special* statements, TODO: what i've missed? if (st->variant() == ASSIGN_STAT) return findUsagesInAssignment(st); if (st->variant() == PROC_STAT) return findUsagesInFuncCall(st->expr(0), st->symbol()->identifier()); else if (!isDVM_stat(st) && !isSPF_stat(st)) { VarUsages st_usages; for (int i = 0; i < 3; ++i) st_usages.extend(findUsagesInExpr(st->expr(i))); return st_usages; } return VarUsages(); } VarUsages ReadWriteAnalyzer::findUsagesInAssignment(SgStatement* st) const { // load read & writes from the right part VarUsages usages = findUsagesInExpr(st->expr(1)); // load usages from array indexes VarUsages usages_in_arr_indexing = findUsagesInExpr(st->expr(1)->lhs()); usages.extend(usages_in_arr_indexing); usages_in_arr_indexing = findUsagesInExpr(st->expr(1)->rhs()); usages.extend(usages_in_arr_indexing); usages_in_arr_indexing = findUsagesInExpr(st->expr(0)->lhs()); usages.extend(usages_in_arr_indexing); usages_in_arr_indexing = findUsagesInExpr(st->expr(0)->rhs()); usages.extend(usages_in_arr_indexing); // finally add explicitly modified var auto ex = st->expr(0); auto s = st->expr(0)->symbol(); if (s && (ex->variant() == VAR_REF || isArrayRef(ex))) usages.insert_write(ex); return usages; } VarUsages ReadWriteAnalyzer::findUsagesInExpr(SgExpression* exp) const { VarUsages usages; queue buf; buf.push(exp); while (!buf.empty()) { SgExpression* cur = buf.front(); buf.pop(); if (!cur) continue; const int e_type = cur->variant(); if (e_type == VAR_REF || isArrayRef(cur)) usages.insert_read(cur); else if (e_type == FUNC_CALL) usages.extend(findUsagesInFuncCall(cur->lhs(), cur->symbol()->identifier())); buf.push(cur->lhs()); buf.push(cur->rhs()); } return usages; } void ReadWriteAnalyzer::findReadUsagesInExpression(SgExpression* ex, VarUsages& usages) const { if (ex) { if (ex->variant() == VAR_REF || ex->variant() == ARRAY_REF) usages.insert_read(ex); findReadUsagesInExpression(ex->lhs(), usages); findReadUsagesInExpression(ex->rhs(), usages); } } //TODO: need to improve to MPI_* functions VarUsages ReadWriteAnalyzer::findUsagesInFuncCall(SgExpression* params_tree, const string& func_key) const { VarUsages usages; vector inOutTypes; bool isIntrinsic = isIntrinsicFunctionName(func_key.c_str()); if (!isIntrinsic) { auto it = modified_pars.find(func_key); if (it != modified_pars.end()) inOutTypes = it->second; } else if (isMpiFunction(func_key.c_str())) { if (func_key == "mpi_abort") inOutTypes = { IN_BIT, IN_BIT, OUT_BIT }; if (func_key == "mpi_send") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; if (func_key == "mpi_isend") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_recv") inOutTypes = { IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_irecv") inOutTypes = { IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_alltoall") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_alltoallv") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_allgather") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_allgatherv") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_allreduce") inOutTypes = { IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_reduce") inOutTypes = { IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_reduce_scatter") inOutTypes = { IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_scatter") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_scatterv") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_gather") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_gatherv") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_sendrecv") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_sendrecv_replace") inOutTypes = { IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_scan") inOutTypes = { IN_BIT, IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT | OUT_BIT }; else if (func_key == "mpi_bcast") inOutTypes = { IN_BIT | OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT }; else if (func_key == "mpi_bsend") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT }; else if (func_key == "mpi_bsend_init") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT }; else if (func_key == "mpi_ibsend") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT }; else if (func_key == "mpi_irsend") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT }; else if (func_key == "mpi_issend") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT }; else if (func_key == "mpi_recv_init") inOutTypes = { OUT_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT }; else if (func_key == "mpi_rsend") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT }; else if (func_key == "mpi_rsend_init") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT }; else if (func_key == "mpi_send_init") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT }; else if (func_key == "mpi_ssend") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT }; else if (func_key == "mpi_ssend_init") inOutTypes = { IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, IN_BIT, OUT_BIT }; } int param_no = 0; while (params_tree) { SgExpression* param = params_tree->lhs(); if (param->variant() == VAR_REF || isArrayRef(param)) { if (inOutTypes.size()) { if (param_no >= inOutTypes.size()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (FuncParam::isArgIn((int64_t)inOutTypes[param_no])) usages.insert_read(param); if (FuncParam::isArgOut((int64_t)inOutTypes[param_no])) usages.insert_write(param); } else { usages.insert_read(param); if (!isIntrinsic) usages.insert_write(param); } findReadUsagesInExpression(param->lhs(), usages); findReadUsagesInExpression(param->rhs(), usages); } param_no++; params_tree = params_tree->rhs(); } return usages; } VarUsages ReadWriteAnalyzer::get_usages(SgStatement* st) { if (initialized.find(st->fileName()) == initialized.end()) init(st->getFile()); VarUsages usages; // if statement is compound if (compound_statements.find(st->variant()) != compound_statements.end()) usages = gatherUsagesForCompound(st); else { auto it = usages_by_statement.find(st); if (it == usages_by_statement.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); usages = it->second; } return usages; } VarUsages ReadWriteAnalyzer::get_usages(vector &statements) { auto usages = VarUsages(); for (auto& st : statements) { auto st_usages = get_usages(st); usages.extend(st_usages); } return usages; } VarUsages ReadWriteAnalyzer::gatherUsagesForCompound(SgStatement* compoundStatement) const { VarUsages all_usages; SgStatement* last = compoundStatement->lastNodeOfStmt(); SgStatement* runner = compoundStatement; while (runner != last) { if (runner->variant() == CONTAINS_STMT) break; if (!isSgExecutableStatement(runner) || isDVM_stat(runner) || isSPF_stat(runner)) { runner = runner->lexNext(); continue; } all_usages.extend(findUsagesInStatement(runner)); runner = runner->lexNext(); } return all_usages; } void ReadWriteAnalyzer::print() const { auto save = current_file->filename(); for (int i = 0; i < CurrentProject->numberOfFiles(); i++) { printf("file: %s\n", CurrentProject->file(i).filename()); for (int j = 0; j < CurrentProject->file(i).numberOfFunctions(); j++) { printf("function: %s\n", CurrentProject->file(i).functions(j)->symbol()->identifier()); SgStatement* runner = CurrentProject->file(i).functions(j); auto last = runner->lastNodeOfStmt(); while (runner != last) { if (runner->variant() == CONTAINS_STMT) break; auto it = usages_by_statement.find(runner); if (it != usages_by_statement.end()) { runner->unparsestdout(); it->second.print(); } runner = runner->lexNext(); } } } if (SgFile::switchToFile(save) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } map> ReadWriteAnalyzer::load_modified_pars(const map> &files) { map> res; for (auto& funcs : files) { string file_name = funcs.first; for (auto& func : funcs.second) { string func_key = func->funcName; res[func_key] = func->funcParams.inout_types; } } return res; }