diff --git a/CMakeLists.txt b/CMakeLists.txt index ba85c74..03afe1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -228,6 +228,8 @@ set(TRANSFORMS set(CFG src/CFGraph/IR.cpp src/CFGraph/IR.h + src/CFGraph/IR_domTree.cpp + src/CFGraph/IR_domTree.h src/CFGraph/CFGraph.cpp src/CFGraph/CFGraph.h src/CFGraph/RD_subst.cpp diff --git a/src/CFGraph/CFGraph.cpp b/src/CFGraph/CFGraph.cpp index a529705..6fc4682 100644 --- a/src/CFGraph/CFGraph.cpp +++ b/src/CFGraph/CFGraph.cpp @@ -1149,6 +1149,16 @@ map> buildCFG(const map& common if (settings.withRD) buildReachingDefs(result, settings); + if (settings.withDominators) + { + auto t = high_resolution_clock::now(); + for (auto& [func, bblocks] : result) + SAPFOR::buildDominatorTree(bblocks); + + auto msec = duration_cast(high_resolution_clock::now() - t).count(); + __spf_print(1, " dominator build time is %.3f sec\n", msec / 1000.); + } + if (SgFile::switchToFile(oldFile) == -1) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); diff --git a/src/CFGraph/CFGraph.h b/src/CFGraph/CFGraph.h index 319b420..8dfeb6a 100644 --- a/src/CFGraph/CFGraph.h +++ b/src/CFGraph/CFGraph.h @@ -6,6 +6,7 @@ #include #include "IR.h" +#include "IR_domTree.h" namespace SAPFOR { @@ -24,7 +25,7 @@ namespace SAPFOR std::vector next; std::vector prev; - + BasicBlock* directDominator = NULL; //reaching definition std::map> RD_in, RD_out; @@ -34,6 +35,7 @@ namespace SAPFOR bool addLive(const std::map>& to_add, bool in); std::map> getLive(bool in) const; bool removeLive(SAPFOR::Argument* to_remove, bool in); + public: BasicBlock() { num = lastNumBlock++; } BasicBlock(IR_Block* item); @@ -42,6 +44,7 @@ namespace SAPFOR void addInstruction(IR_Block* item); void addPrev(BasicBlock* prev_) { prev.push_back(prev_); } void addNext(BasicBlock* next_) { next.push_back(next_); } + void setDom(BasicBlock* dom) { directDominator = dom; } int removePrev(BasicBlock* removed); int removeNext(BasicBlock* removed); @@ -69,7 +72,11 @@ namespace SAPFOR const std::vector& getInstructions() const { return instructions; } const std::vector& getNext() const { return next; } const std::vector& getPrev() const { return prev; } - + BasicBlock* getDom() const + { + return directDominator; + } + /* * FOR LIVE ANALYSIS */ @@ -105,13 +112,15 @@ namespace SAPFOR bool withDVM = false; bool withCallsInBlocks = false; // separate each F_CALL to own BasicBlock bool withCallFrom = true; + bool withDominators = true; explicit CFG_Settings(int) { } explicit CFG_Settings(bool atLeastOneIterInLoop = false, bool withRD = true, bool withRegisters = false, - bool withDVM = false, bool withSPF = false, bool withCallsInBlocks = false, bool withCallFrom = true) : + bool withDVM = false, bool withSPF = false, bool withCallsInBlocks = false, + bool withCallFrom = true, bool withDominators = true) : atLeastOneIterInLoop(atLeastOneIterInLoop), withRD(withRD), withRegisters(withRegisters), withDVM(withDVM), withSPF(withSPF), - withCallsInBlocks(withCallsInBlocks), withCallFrom(withCallFrom) + withCallsInBlocks(withCallsInBlocks), withCallFrom(withCallFrom), withDominators(withDominators) { } }; } @@ -146,4 +155,4 @@ static inline void deleteCFG(std::mapgetNext()) { + if (dfs_num[w] == -1) + DFS(w, dfs_num[v]); + } + } + + void DominatorFinder::Compress(int v) { + if (ancestor[ancestor[v]] != -1) { + Compress(ancestor[v]); + + if (semi[label[ancestor[v]]] < semi[label[v]]) + label[v] = label[ancestor[v]]; + ancestor[v] = ancestor[ancestor[v]]; + } + } + + int DominatorFinder::Eval(int v) { + if (ancestor[v] == -1) + return v; + + Compress(v); + return label[v]; + } + + void DominatorFinder::Link(int v, int w) { + ancestor[w] = v; + } + + DominatorFinder::DominatorFinder(std::vector& blocks) { + if (blocks.empty()) + return; + + entry = blocks[0]; + n = 0; + + for (auto block : blocks) + dfs_num[block] = -1; + + int max_size = blocks.size(); + vertices.resize(max_size); + parent.assign(max_size, -1); + semi.assign(max_size, -1); + vertex.assign(max_size, -1); + ancestor.assign(max_size, -1); + label.assign(max_size, -1); + bucket.resize(max_size); + + DFS(entry, -1); + + for (int i = n - 1; i > 0; --i) { + int w = vertex[i]; + + for (BasicBlock* v : vertices[w]->getPrev()) { + if (dfs_num[v] == -1) + continue; + int u = Eval(dfs_num[v]); + + if (semi[u] < semi[w]) + semi[w] = semi[u]; + } + + bucket[vertex[semi[w]]].push_back(w); + Link(parent[w], w); + + for (int v : bucket[parent[w]]) + { + int u = Eval(v); + if (semi[u] < semi[v]) + vertices[v]->setDom(vertices[u]); + else + vertices[v]->setDom(vertices[parent[w]]); + } + bucket[parent[w]].clear(); + } + + for (int i = 1; i < n; ++i) { + int w = vertex[i]; + + if (vertices[w]->getDom() != vertices[vertex[semi[w]]]) + vertices[w]->setDom(vertices[w]->getDom()->getDom()); + } + + entry->setDom(nullptr); + } + + void buildDominatorTree(std::vector& blocks) { + DominatorFinder finder(blocks); + } +} diff --git a/src/CFGraph/IR_domTree.h b/src/CFGraph/IR_domTree.h new file mode 100644 index 0000000..78a2c8b --- /dev/null +++ b/src/CFGraph/IR_domTree.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +#include "CFGraph.h" + +// Lengauer, Thomas. A fast algorithm for finding dominators in a flowgraph / Thomas Lengauer, Robert Endre Tarjan +// ACM Transactions on Programming Languages and Systems (TOPLAS). — 1979. — Vol. 1, no. 1. — Pp. 121–141. + +namespace SAPFOR { + +class BasicBlock; + +class DominatorFinder { +private: + BasicBlock* entry; + std::vector vertices; + std::unordered_map dfs_num; + std::vector parent, semi, vertex, ancestor, label; + std::vector> bucket; + int n; + + void DFS(BasicBlock* v, int parent_num); + void Compress(int v); + int Eval(int v); + void Link(int v, int w); + +public: + DominatorFinder(std::vector& blocks); +}; + +void buildDominatorTree(std::vector& blocks); +} diff --git a/src/ProjectParameters/projectParameters.cpp b/src/ProjectParameters/projectParameters.cpp index d8d96d9..6de6861 100644 --- a/src/ProjectParameters/projectParameters.cpp +++ b/src/ProjectParameters/projectParameters.cpp @@ -2,16 +2,20 @@ #include #include -#include #include #include #include #include +#include #include #include #include +#include "CFGraph/CFGraph.h" +#include "CFGraph/IR.h" +#include "Distribution/Array.h" #include "dvm.h" + #include "errors.h" #include "SgUtils.h" #include "graph_calls.h" @@ -19,15 +23,418 @@ #include "projectParameters.h" -using namespace std; +using std::set; +using std::map; +using std::string; +using std::vector; +using std::tuple; +using std::pair; +using std::make_tuple; +using std::find_if; -map< pair, set> - findParameters(const map> &defUseByFunctions, - const map &commonBlocks, - const map> &allFuncInfo) +static map> call_sites; + +enum class MODE { - map< pair, set> foundParameters; - - - return foundParameters; -} \ No newline at end of file + BEFORE, + AFTER +}; + +static tuple +stmtToIR(const map>& CFGraph, SgStatement* stmt) +{ + SgStatement* cur = stmt; + cur->switchToFile(); + while (cur->variant() != PROC_HEDR && cur->variant() != PROG_HEDR && cur->variant() != FUNC_HEDR) + cur = cur->controlParent(); + + string funcName = ((SgProcHedrStmt*)cur)->nameWithContains(); + + int stmtID = stmt->id(); + for (const auto& [func, bblocks] : CFGraph) + { + if (func->funcName != funcName) + continue; + + for (auto basicBlock : bblocks) + for (auto ins : basicBlock->getInstructions()) + if (stmtID == ins->getInstruction()->getOperator()->id()) + return make_tuple(func, ins->getInstruction(), basicBlock); + } + + printInternalError(convertFileName(__FILE__).c_str(), __LINE__); + return { NULL, NULL, NULL }; +} + +static tuple +IRByNumber(const map>& CFGraph, int num) +{ + if (num < 0) + return { NULL, NULL, NULL }; + + for (const auto& [func, bblocks] : CFGraph) + for (auto byBB : bblocks) + if (byBB->getInstructions().front()->getNumber() <= num && byBB->getInstructions().back()->getNumber() >= num) + return make_tuple(func, getInstructionByNumber(byBB->getInstructions(), num), byBB); + + printInternalError(convertFileName(__FILE__).c_str(), __LINE__); + return { NULL, NULL, NULL }; +} + +template +static void processArgument(set& worklist, + SAPFOR::Argument* arg, + Iterator instr, Iterator first_instr) +{ + if (arg == NULL) + return; + + if (arg->getType() == SAPFOR::CFG_ARG_TYPE::REG) + extract_vars_from_reg(worklist, arg, instr, first_instr); + else if (arg->getType() == SAPFOR::CFG_ARG_TYPE::VAR) + worklist.insert(arg); +} + +template +static void extract_vars_from_reg(set& worklist, + SAPFOR::Argument* reg, + Iterator instr, Iterator first_instr) +{ + for (; instr >= first_instr; instr--) + { + if ((*instr)->getInstruction()->getResult() == reg) + { + processArgument(worklist, (*instr)->getInstruction()->getArg1(), instr, first_instr); + processArgument(worklist, (*instr)->getInstruction()->getArg2(), instr, first_instr); + return; + } + } +} + +static void lookup_for_vars(set>& where_to_add, + set& worklist, + SAPFOR::Instruction* instr, + SAPFOR::BasicBlock* bblock, + FuncInfo* cur_func, + const map>& fullIR) +{ + while (bblock) + { + auto first_instr = bblock->getInstructions().begin(); + auto cur_instr = find_if(first_instr, bblock->getInstructions().end(), [instr](SAPFOR::IR_Block* i) { + return i->getInstruction() == instr; + }); + + for (; cur_instr >= bblock->getInstructions().begin(); --cur_instr) + { + auto instr = (*cur_instr)->getInstruction(); + auto result_arg = instr->getResult(); + auto arg1 = instr->getArg1(); + auto arg2 = instr->getArg2(); + + if (worklist.count(result_arg)) + { + worklist.erase(result_arg); + processArgument(worklist, arg1, cur_instr, first_instr); + processArgument(worklist, arg2, cur_instr, first_instr); + } + + if (instr->getOperation() == SAPFOR::CFG_OP::PARAM && worklist.count(arg1)) + { + // skip to F_CALL + auto f_call_instr = cur_instr; + while ((*f_call_instr)->getInstruction()->getOperation() != SAPFOR::CFG_OP::F_CALL) + f_call_instr++; + + if ((*f_call_instr)->getInstruction()->getArg1()->getValue() == "_READ") + { + auto stmt_before = (*f_call_instr)->getInstruction()->getOperator(); + auto filename = stmt_before->fileName(); + auto line = stmt_before->lineNumber(); + auto var_name = arg1->getValue().substr(arg1->getValue().find('%') + 1); + __spf_print(1, "Please specify value of variable %s on line %d of file %s\n", arg1->getValue().c_str(), line, filename); + auto toAdd = make_tuple(stmt_before, var_name, MODE::AFTER); + where_to_add.insert(toAdd); + worklist.erase(arg1); + } + } + } + + const auto& RD = bblock->getRD_In(); + map group_by_block; + + set to_erase; + for (auto& arg : worklist) + { + if (RD.count(arg)) + { + if (RD.at(arg).size() == 1 && *RD.at(arg).begin() == SAPFOR::CFG_VAL::UNINIT) + __spf_print(1, "variable %s has no definition\n", arg->getValue().c_str()); + else if (RD.at(arg).size() > 1) + { + auto stmt_after = (*first_instr)->getInstruction()->getOperator(); + auto filename = stmt_after->fileName(); + auto line = stmt_after->lineNumber(); + auto var_name = arg->getValue().substr(arg->getValue().find('%') + 1); + __spf_print(1, "variable %s has multiple reaching definitions, further analysis is impossible\n", arg->getValue().c_str()); + __spf_print(1, "Please specify value of variable %s on line %d of file %s\n", arg->getValue().c_str(), line, filename); + auto toAdd = make_tuple(stmt_after, var_name, MODE::BEFORE); + where_to_add.insert(toAdd); + to_erase.insert(arg); + } + else + { + auto instr_num = *RD.at(arg).begin(); + auto [func, instr, bblock] = IRByNumber(fullIR, instr_num); + if (cur_func == func && (group_by_block[bblock] == NULL || group_by_block[bblock]->getNumber() < instr_num)) + group_by_block[bblock] = instr; + } + } + } + for (const auto& arg : to_erase) + worklist.erase(arg); + + while (bblock && group_by_block.find(bblock) == group_by_block.end()) + bblock = bblock->getDom(); + + if (bblock) + instr = group_by_block[bblock]; + } + + // other variables are from global scope + const auto& RD = fullIR.at(cur_func).front()->getRD_In(); + for (auto& arg : worklist) + { + if (arg->isMemGlobal()) + { + set found_rd; + if (RD.count(arg)) + found_rd = RD.at(arg); + + if (found_rd.size() == 0) + { + auto call_instr = call_sites[cur_func].size() ? call_sites[cur_func].front() : NULL; + while (call_instr && found_rd.size() == 0) + { + auto [call_func, _, call_bblock] = IRByNumber(fullIR, call_instr->getNumber()); + if (call_bblock->getRD_Out().count(arg)) + found_rd = call_bblock->getRD_Out().at(arg); + + + call_instr = call_sites[call_func].size() ? call_sites[call_func].front() : NULL; + } + } + + if (found_rd.size() == 1 && *found_rd.begin() == SAPFOR::CFG_VAL::UNINIT) + __spf_print(1, "variable %s has no definition\n", arg->getValue().c_str()); + else if (found_rd.size() > 1) + { + auto first_instr = fullIR.at(cur_func).front()->getInstructions().begin(); + auto stmt_after = (*first_instr)->getInstruction()->getOperator(); + auto filename = stmt_after->fileName(); + auto line = stmt_after->lineNumber(); + auto var_name = arg->getValue().substr(arg->getValue().find('%') + 1); + __spf_print(1, "variable %s has multiple reaching definitions, further analysis is impossible\n", arg->getValue().c_str()); + __spf_print(1, "Please specify value of variable %s on line %d of file %s\n", arg->getValue().c_str(), line, filename); + auto toAdd = make_tuple(stmt_after, var_name, MODE::BEFORE); + where_to_add.insert(toAdd); + } + else + { + auto instr_num = *found_rd.begin(); + auto [func, instr, bblock] = IRByNumber(fullIR, instr_num); + set new_worklist = { arg }; + + lookup_for_vars(where_to_add, new_worklist, instr, bblock, func, fullIR); + } + } + } + + + for (const auto& call_instr : call_sites[cur_func]) + { + set new_worklist; + auto params_num = cur_func->funcParams.countOfPars; + + auto [call_func, _, call_bblock] = IRByNumber(fullIR, call_instr->getNumber()); + auto first_instr = call_bblock->getInstructions().begin(); + auto cur_instr = find_if(first_instr, call_bblock->getInstructions().end(), [call_instr](SAPFOR::IR_Block* i) { + return i->getInstruction() == call_instr; + }); + + for (auto& arg : worklist) + { + if (arg->getMemType() == SAPFOR::CFG_MEM_TYPE::FUNC_PARAM_) + { + auto param_num = stoi(arg->getValue().substr(arg->getValue().find('%', arg->getValue().find('%') + 1) + 1)); + auto param_instr = (cur_instr - (params_num - param_num)); + auto param_arg = (*param_instr)->getInstruction()->getArg1(); + processArgument(new_worklist, param_arg, param_instr, first_instr); + } + } + lookup_for_vars(where_to_add, new_worklist, call_instr, call_bblock, call_func, fullIR); + } + +} + +static void handle_single_allocate(set>& where_to_add, + SgStatement* alloc_statement, + const map>& fullIR) +{ + auto [func, instr, bblock] = stmtToIR(fullIR, alloc_statement); + + auto first_instr = bblock->getInstructions().begin(); + auto cur_instr = find_if(first_instr, bblock->getInstructions().end(), [instr](SAPFOR::IR_Block* i) { + return i->getInstruction() == instr; + }); + auto alloc_instr = cur_instr; + + // skip to F_CALL _ALLOC n + while ((*alloc_instr)->getInstruction()->getOperation() != SAPFOR::CFG_OP::F_CALL || + (*alloc_instr)->getInstruction()->getArg1()->getValue() != "_ALLOC") + alloc_instr++; + + auto arrays_num = stoi((*alloc_instr)->getInstruction()->getArg2()->getValue()); + + set worklist; + for (int i = 0; i < arrays_num; i++) + { + auto param_instr = --alloc_instr; + auto param_reg = (*param_instr)->getInstruction()->getArg1(); + + while ((*param_instr)->getInstruction()->getOperation() != SAPFOR::CFG_OP::LOAD || + (*param_instr)->getInstruction()->getResult() != param_reg) + param_instr--; + + + auto dimensions_num = stoi((*param_instr)->getInstruction()->getArg2()->getValue()); + + for (int j = 0; j < dimensions_num; j++) + { + auto ref_instr = --param_instr; + if ((*ref_instr)->getInstruction()->getOperation() == SAPFOR::CFG_OP::RANGE) + { + vector range_args = { (*ref_instr)->getInstruction()->getArg1(), + (*ref_instr)->getInstruction()->getArg2(), + (*ref_instr)->getInstruction()->getResult() }; + for (auto& arg : range_args) + processArgument(worklist, arg, ref_instr, first_instr); + + } + else + { + auto arg = (*ref_instr)->getInstruction()->getArg1(); + processArgument(worklist, arg, ref_instr, first_instr); + } + } + } + lookup_for_vars(where_to_add, worklist, instr, bblock, func, fullIR); +} + + +static void handle_single_loop(set>& where_to_add, + SgStatement* loop_stmt, + const map>& fullIR) +{ + auto [func, instr, bblock] = stmtToIR(fullIR, loop_stmt); + auto cur_instr = bblock->getInstructions().end() - 1; + + set worklist; + extract_vars_from_reg(worklist, (*cur_instr)->getInstruction()->getResult(), cur_instr, bblock->getInstructions().begin()); + + lookup_for_vars(where_to_add, worklist, (*cur_instr)->getInstruction(), bblock, func, fullIR); +} + +void findParameters(ResultSet& foundParameters, + map>& fullIR, + const map, pair>& declaredArrays) +{ + set> where_to_add; + + map name_to_func; + for (const auto& [func, _] : fullIR) + name_to_func[func->funcName] = func; + + for (auto& [func, bblocks] : fullIR) + { + for (const auto& block : bblocks) + { + for (const auto& ir_block : block->getInstructions()) + { + auto instr = ir_block->getInstruction(); + if (instr->getOperation() == SAPFOR::CFG_OP::F_CALL) + { + auto func_name = instr->getArg1()->getValue(); + auto func_info = name_to_func.find(func_name); + + if (func_info != name_to_func.end()) + call_sites[func_info->second].push_back(instr); + } + } + } + } + + set alloc_statements; + for (const auto& [func, bblocks] : fullIR) + { + for (const auto& block : bblocks) + { + for (auto instr = block->getInstructions().begin(); instr != block->getInstructions().end(); ++instr) + { + auto op = (*instr)->getInstruction()->getOperator(); + if (op && op->variant() == ALLOCATE_STMT) + alloc_statements.insert(op); + } + } + } + + set for_statements; + // Find all FOR statements in the program + for (const auto& [func, bblocks] : fullIR) + { + for (const auto& block : bblocks) + { + for (auto instr = block->getInstructions().begin(); instr != block->getInstructions().end(); ++instr) + { + auto op = (*instr)->getInstruction()->getOperator(); + if (op && op->variant() == FOR_NODE) + for_statements.insert(op); + } + } + } + + for (const auto& alloc_statement : alloc_statements) + handle_single_allocate(where_to_add, alloc_statement, fullIR); + + for (const auto& stmt : for_statements) + handle_single_loop(where_to_add, stmt, fullIR); + + for (const auto& [stmt_before, var_name, mode] : where_to_add) + { + stmt_before->switchToFile(); + + SgVariableSymb* var_symb = new SgVariableSymb(var_name.c_str()); + SgVarRefExp* var = new SgVarRefExp(var_symb); + SgExprListExp* ex = new SgExprListExp(); + auto assgn_op = new SgExpression(ASSGN_OP, var, NULL); + ex->setLhs(assgn_op); + + SgExpression* parameter_op = new SgExpression(SPF_PARAMETER_OP, ex); + auto dir_list = new SgExprListExp(); + dir_list->setLhs(parameter_op); + SgStatement* toAdd = new SgStatement(SPF_ANALYSIS_DIR, NULL, NULL, dir_list, NULL, NULL); + + toAdd->setlineNumber(stmt_before->lineNumber()); + toAdd->setLocalLineNumber(stmt_before->lineNumber()); + toAdd->setFileId(stmt_before->getFileId()); + toAdd->setProject(stmt_before->getProject()); + + //NOTE: only for debbuging, results will be transferred to the visualizer + /*if (mode == MODE::AFTER) + stmt_before->insertStmtAfter(*toAdd, *stmt_before->controlParent()); + else + stmt_before->insertStmtBefore(*toAdd, *stmt_before->controlParent());*/ + + foundParameters.insert(make_tuple(stmt_before->fileName(), stmt_before->lineNumber(), var_name)); + } +} diff --git a/src/ProjectParameters/projectParameters.h b/src/ProjectParameters/projectParameters.h index 5a240b0..5be0d3c 100644 --- a/src/ProjectParameters/projectParameters.h +++ b/src/ProjectParameters/projectParameters.h @@ -1,3 +1,14 @@ #pragma once -std::map< std::pair, std::set> findParameters(const std::map> &defUseByFunctions, const std::map &commonBlocks, const std::map> &allFuncInfo); \ No newline at end of file +#include +#include +#include +#include + +#include "../GraphCall/graph_calls.h" + +using ResultSet = std::set>; + +void findParameters(ResultSet& foundParameters, + std::map>& fullIR, + const std::map, std::pair>& declaredArrays); diff --git a/src/Sapfor.cpp b/src/Sapfor.cpp index 519c10e..961964f 100644 --- a/src/Sapfor.cpp +++ b/src/Sapfor.cpp @@ -1895,7 +1895,7 @@ static bool runAnalysis(SgProject &project, const int curr_regime, const bool ne else if (curr_regime == RENAME_SYMBOLS) runRenameSymbols(&project, commonBlocks); else if (curr_regime == FIND_PARAMETERS) - parametersOfProject = findParameters(defUseByFunctions, commonBlocks, allFuncInfo); + findParameters(parametersOfProject, fullIR, declaredArrays); else if (curr_regime == BUILD_IR) { auto CFG_forFile = buildCFG(commonBlocks, allFuncInfo_IR, SAPFOR::CFG_Settings(0)); diff --git a/src/SapforData.h b/src/SapforData.h index b62ae99..36c1a24 100644 --- a/src/SapforData.h +++ b/src/SapforData.h @@ -169,7 +169,7 @@ std::map filesInfo; // information about open,close,write and re // //for FIND_PARAMETERS -std::map< std::pair, std::set> parametersOfProject; // [file, line] -> set[vars] +std::set> parametersOfProject; // [file, line, varname] // //for GET_MIN_MAX_BLOCK_DIST diff --git a/src/Utils/CommonBlock.h b/src/Utils/CommonBlock.h index 196f3b9..7b89792 100644 --- a/src/Utils/CommonBlock.h +++ b/src/Utils/CommonBlock.h @@ -1,5 +1,7 @@ #pragma once +#include "../Distribution/Array.h" + enum varType { SCALAR, ARRAY, CONST, ANOTHER }; struct CommonVariableUse diff --git a/src/Utils/version.h b/src/Utils/version.h index 4f8972a..ad1744c 100644 --- a/src/Utils/version.h +++ b/src/Utils/version.h @@ -1,3 +1,3 @@ #pragma once -#define VERSION_SPF "2424" +#define VERSION_SPF "2425" diff --git a/tests/sapfor/parameter/dynamic_array_maximum.f90 b/tests/sapfor/parameter/dynamic_array_maximum.f90 new file mode 100644 index 0000000..f49e5e3 --- /dev/null +++ b/tests/sapfor/parameter/dynamic_array_maximum.f90 @@ -0,0 +1,52 @@ +program dynamic_array_maximum_3d + implicit none + integer :: n1, n2, n3, n4 , k, i, j, l, a + integer :: sum3 + real :: max_element + real, allocatable :: array(:,:,:), array2(:,:,:), array3(:,:,:) + + write(*, *) "Enter 3 integers" + read(*, *) n, m, k + m = 100 + + if (1 .eq. 1) then + a = 3 + else if (2 .eq. 1) then + a = 4 + endif + + m = m + 1 + k = m * 1000 + n * 10 + + allocate(array(n, m + n, k + m + n), & + &array2(k, m + n, k), & + &array3(k, m, k + n)) + + call random_seed() + do i = 1, n1 + do j = 1, m * n1 + do l = 1, k * m * n1 + call random_number(array(i,j,l)) + array(i,j,l) = int(array(i,j,l) * 100) + end do + end do + end do + + max_element = array(1,1,1) + do i = 1, n1 + do j = 1, m + do l = 1, k + max_element = MAX(array(i,j,l), max_element) + end do + end do + end do + deallocate(array, array2, array3) + write(*, *) max_element +end program dynamic_array_maximum_3d + +! function sum3(x, y, z) +! implicit none +! integer :: x, y, z +! integer :: sum3 +! sum3 = x + y + z +! end function sum3