#include "private_arrays_resizing.h" #include "../GraphLoop/graph_loops.h" #include "../Utils/SgUtils.h" #include "../Utils/utils.h" #include "../Utils/errors.h" #include "../DirectiveProcessing/directive_parser.h" #include "../LoopAnalyzer/loop_analyzer.h" #include #include #include using std::string; using std::set; using std::map; using std::queue; using std::vector; using std::pair; using std::make_pair; static void printExp(SgExpression *exp) { queue qq; qq.push(exp); printf("Expression: "); while (!qq.empty()) { SgExpression *exp = qq.front(); qq.pop(); printf("[%s]: %s\n", tag[exp->variant()], exp->unparse()); if (exp->variant() == TYPE_OP) if (exp->symbol()) printf("%s, %s", exp->symbol()->identifier(), tag[exp->symbol()->variant()]); if (exp->lhs()) qq.push(exp->lhs()); if (exp->rhs()) qq.push(exp->rhs()); } } static void printSt(SgStatement *st) { printf("Statement [%s]: %s\n", tag[st->variant()], st->unparse()); queue qq; for (int i = 0; i < 3; ++i) { if (st->expr(i)) { printf("[%d,%s]: %s\n", i, tag[st->expr(i)->variant()], st->expr(i)->unparse()); qq.push(st->expr(i)); } } while (!qq.empty()) { SgExpression *exp = qq.front(); qq.pop(); printf("[%s]: %s\n", tag[exp->variant()], exp->unparse()); if (exp->variant() == TYPE_OP) if (exp->symbol()) printf("%s, %s", exp->symbol()->identifier(), tag[exp->symbol()->variant()]); if (exp->lhs()) qq.push(exp->lhs()); if (exp->rhs()) qq.push(exp->rhs()); } } static void fillIterationVariables(const LoopGraph* loop, set& vars, int dimensions = -1) { if (dimensions == -1) { vars.insert(loop->loopSymbol); for (LoopGraph* child : loop->children) fillIterationVariables(child, vars); } else { for (int i = 0; i < dimensions; ++i) { vars.insert(loop->loopSymbol); if (i != dimensions - 1) loop = loop->children[0]; } } } static SgExpression* findSymbol(SgSymbol* symbol, SgExpression* list) { if (list) { if (list->variant() == VAR_REF || list->variant() == ARRAY_REF) { if (isEqSymbols(list->symbol(), symbol)) return list; } auto left = findSymbol(symbol, list->lhs()); if (left) return left; auto right = findSymbol(symbol, list->rhs()); if (right) return right; } return NULL; } static char* constructNewArrayName(const char *oldName, bool isExpansion) { string name(oldName), newName; name += isExpansion ? "_ex" : "_sh"; newName = name + std::to_string(1); for (int n = 2; ifSymbolExists(current_file, newName); ++n) newName = name + std::to_string(n); char* newNameChar = (char*)malloc((newName.size() + 1) * sizeof(char)); addToCollection(__LINE__, __FILE__, newNameChar, 0); if (newNameChar) strcpy(newNameChar, newName.c_str()); else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); return newNameChar; } static const string constructNewBoundName(const char *oldName, int loopLineNumber, const char *add) { string name(oldName), newName; name += "_" + std::to_string(loopLineNumber); name += add; // start ? "_start" : "_end"; newName = name; for (int n = 0; ifSymbolExists(current_file, newName); ++n) newName = name + "_" + std::to_string(n); return newName; } static SgSymbol* createNewArrayNameSymbol(SgExpression* declaration, bool isExpansion, bool canBeStatic) { SgType* type = new SgType(T_ARRAY); char* newNameStr = constructNewArrayName(declaration->symbol()->identifier(), isExpansion); SgSymbol* newName = new SgSymbol(VARIABLE_NAME, newNameStr, type, NULL); auto attrs = declaration->symbol()->attributes(); if (!canBeStatic) attrs |= ALLOCATABLE_BIT; newName->setAttribute(attrs); return newName; } static void fillLoopBoundExprs(const LoopGraph* forLoop, int depthOfResize, const vector& indexes, vector& bounds) { const LoopGraph* curLoop = forLoop; for (int i = 0; i < depthOfResize; i++) { SgForStmt* loopStmt = (SgForStmt*)curLoop->loop->GetOriginal(); for (int j = 0; j < indexes.size(); j++) { if (indexes[j] && isEqSymbols(loopStmt->doName(), indexes[j])) { //TODO: add MIN and MAX call for bounds if (curLoop->stepVal == 0) { __spf_print(1, "unknown step sign of loop on line %d\n", curLoop->lineNum); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } if (curLoop->stepVal > 0) bounds[j] = new SgExpression(DDOT, loopStmt->start()->copyPtr(), loopStmt->end()->copyPtr(), NULL); else bounds[j] = new SgExpression(DDOT, loopStmt->end()->copyPtr(), loopStmt->start()->copyPtr(), NULL); break; } } if (i != depthOfResize - 1) curLoop = curLoop->children[0]; } } static SgExpression* constructArrayRefTailWithLoopBounds(const LoopGraph* forLoop, int depthOfResize, const vector& indexes, SgExpression* oldTail) { vector dims(indexes.size()); fillLoopBoundExprs(forLoop, depthOfResize, indexes, dims); for (int i = 0; i < indexes.size(); i++) { if (dims[i] == NULL) { dims[i] = oldTail->lhs(); oldTail = oldTail->rhs(); } } SgExpression* newTail = NULL; for (int i = indexes.size() - 1; i >= 0; i--) newTail = new SgExpression(EXPR_LIST, dims[i], newTail); return newTail; } static void extendArrayDeclaration(const LoopGraph* forLoop, bool canBeStatic, const vector& indexes, SgExpression*& exprToExtend, SgSymbol* newArraySym) { exprToExtend->setSymbol(newArraySym); int depthOfResize = 0; for (int i = 0; i < indexes.size(); i++) if (indexes[i] != NULL) depthOfResize++; SgExpression* newTail = NULL; if (canBeStatic) { SgExpression* oldTail = exprToExtend->lhs(); newTail = constructArrayRefTailWithLoopBounds(forLoop, depthOfResize, indexes, oldTail); } else { for (int i = 0; i < indexes.size(); i++) { SgExpression* ddotExpr = new SgExpression(DDOT); newTail = new SgExpression(EXPR_LIST, ddotExpr, newTail); } } exprToExtend = new SgArrayRefExp(*newArraySym); exprToExtend->setLhs(newTail); } static void reduceArray(const vector &indexes, SgExpression *expressionToReduce, SgSymbol *newSymbol) { expressionToReduce->setSymbol(newSymbol); vector tailVec(0); SgExpression *tail = expressionToReduce->lhs(); for (int i = 0; i < indexes.size(); ++i) { if (indexes[i] == 0) tailVec.push_back(tail->lhs()); tail = tail->rhs(); } std::reverse(tailVec.begin(), tailVec.end()); SgExpression *list = makeExprList(tailVec, false); expressionToReduce->setLhs(list); } static SgExpression* constructExtendedArrayRefTail(SgExpression* oldTail, const vector& indexes) { vector dims(indexes.size()); for (int i = 0; i < indexes.size(); i++) { if (indexes[i] == NULL) { dims[i] = oldTail->lhs(); oldTail = oldTail->rhs(); } else dims[i] = new SgVarRefExp(indexes[i]); } SgExpression* newTail = NULL; for (int i = indexes.size() - 1; i >= 0; i--) newTail = new SgExpression(EXPR_LIST, dims[i], newTail); return newTail; } static void extendArrayRef(const vector& indexes, SgExpression*& expressionToExtend, SgSymbol* newSymbol, const vector& lowBounds) { SgExpression* newTail = constructExtendedArrayRefTail(expressionToExtend->lhs(), indexes); SgExpression* oldTail = expressionToExtend->lhs(); if (oldTail == NULL) { if (expressionToExtend->variant() == VAR_REF) // create array from scalar { expressionToExtend = new SgArrayRefExp(*newSymbol); expressionToExtend->setLhs(newTail); } else if (isArrayRef(expressionToExtend)) // create array from full array ref { SgArrayRefExp* curr = (SgArrayRefExp*)expressionToExtend; expressionToExtend->setSymbol(newSymbol); for (auto& elem : lowBounds) // add low bounds curr->addSubscript(*elem); curr->addSubscript(*newTail); } else printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } else { expressionToExtend->setLhs(newTail); expressionToExtend->setSymbol(newSymbol); } } static bool isAllocatable(SgSymbol* symbol) { return (symbol->attributes() & ALLOCATABLE_BIT) != 0; } static bool isAllocatable(SgStatement *decl) { SgExpression *params = decl->expr(2); while (params != NULL) { if (params->lhs()->variant() == ALLOCATABLE_OP) return true; params = params->rhs(); } return false; } static void setAllocatable(SgStatement *newDecl, SgSymbol *origSymbol) { if (isAllocatable(origSymbol)) return; SgExpression *params = newDecl->expr(2); SgExpression newParams (EXPR_LIST, new SgExpression(ALLOCATABLE_OP), params, (SgSymbol*)NULL); newDecl->setExpression(2, newParams); //объявление с DIMENSION или с ALLOCATABLBE if (newDecl->variant() != VAR_DECL) { newDecl->setVariant(VAR_DECL); if (origSymbol->type()->hasBaseType()) newDecl->setExpression(1, *(new SgTypeExp(*origSymbol->type()->baseType()))); else newDecl->setExpression(1, *(new SgTypeExp(*origSymbol->type()))); } } static SgExpression* checkArrayDecl(SgExpression* array, SgSymbol* arraySymbol, SgStatement* checkedDecl) { if (array->lhs() == NULL) { vector allDecls; auto mainDecl = declaratedInStmt(arraySymbol, &allDecls); if (allDecls.size() == 0) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (allDecls.size() == 1) { array = findSymbol(arraySymbol, mainDecl->expr(0)); checkNull(array, convertFileName(__FILE__).c_str(), __LINE__); return array; } for (auto& decl : allDecls) { if (decl == mainDecl) continue; if (decl == checkedDecl) continue; array = findSymbol(arraySymbol, decl->expr(0)); if (array->lhs()) break; array = NULL; } checkNull(array, convertFileName(__FILE__).c_str(), __LINE__); } return array; } static SgSymbol* alterExtendArrayDeclaration(const LoopGraph* forLoop, SgStatement* declarationStmt, SgSymbol* arraySymbol, bool canBeStatic, const vector& indexes) { SgSymbol* newArraySymbol = NULL; SgExpression* array = findSymbol(arraySymbol, declarationStmt->expr(0)); array = checkArrayDecl(array, arraySymbol, declarationStmt); SgExpression* newArray = array->copyPtr(); newArraySymbol = createNewArrayNameSymbol(newArray, true, canBeStatic); if (newArraySymbol == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); extendArrayDeclaration(forLoop, canBeStatic, indexes, newArray, newArraySymbol); SgExpression newExprList(EXPR_LIST, newArray, (SgExpression*)NULL, (SgSymbol*)NULL); declarationStmt->setExpression(0, newExprList); if (!canBeStatic) setAllocatable(declarationStmt, arraySymbol); return newArraySymbol; } static SgSymbol* alterShrinkArrayDeclaration(SgStatement *declarationStatement, SgSymbol *arraySymbol, vector &dimensions, bool canBeStatic) { SgSymbol *newArraySymbol = NULL; SgExpression *array = findSymbol(arraySymbol, declarationStatement->expr(0)); SgExpression *newArray = array->copyPtr(); newArraySymbol = createNewArrayNameSymbol(newArray, false, canBeStatic); reduceArray(dimensions, newArray, newArraySymbol); SgExpression newExprList(EXPR_LIST, newArray, (SgExpression*)NULL, (SgSymbol*)NULL); declarationStatement->setExpression(0, newExprList); if (newArraySymbol == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); return newArraySymbol; } static void extendArrayRefsInExpr(const vector& indexes, SgExpression*& expr, SgSymbol* arraySymbol, SgSymbol* newArraySymbol, const vector& lowBounds, int line) { if (expr) { if (expr->variant() == FUNC_CALL) { SgFunctionCallExp* call = isSgFunctionCallExp(expr); for (int arg = 0; arg < call->numberOfArgs(); ++arg) { auto argRef = call->arg(arg); if ((isArrayRef(argRef) || argRef->variant() == VAR_REF) && isEqSymbols(argRef->symbol(), arraySymbol)) { __spf_print(1, "unsupported private array extension under call on line %d\n", line); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } } } SgExpression* left = expr->lhs(); extendArrayRefsInExpr(indexes, left, arraySymbol, newArraySymbol, lowBounds, line); if (left != expr->lhs()) expr->setLhs(left); SgExpression* right = expr->rhs(); extendArrayRefsInExpr(indexes, right, arraySymbol, newArraySymbol, lowBounds, line); if (right != expr->rhs()) expr->setRhs(right); if (isArrayRef(expr) && isEqSymbols(arraySymbol, expr->symbol())) extendArrayRef(indexes, expr, newArraySymbol, lowBounds); else if (expr->variant() == VAR_REF && isEqSymbols(arraySymbol, expr->symbol())) extendArrayRef(indexes, expr, newArraySymbol, lowBounds); } } static void extendArrayRefs(const vector &indexes, SgStatement *st, SgSymbol *arraySymbol, SgSymbol *newArraySymbol, const vector &lowBounds) { for (int i = 0; i < 3; ++i) { if (st->variant() == PROC_STAT) { SgCallStmt* call = isSgCallStmt(st); for (int arg = 0; arg < call->numberOfArgs(); ++arg) { auto argRef = call->arg(arg); if ((isArrayRef(argRef) || argRef->variant() == VAR_REF) && isEqSymbols(argRef->symbol(), arraySymbol)) { __spf_print(1, "unsupported private array extension under call on line %d\n", st->lineNumber()); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } } } if (st->expr(i)) { SgExpression* ex = st->expr(i); extendArrayRefsInExpr(indexes, ex, arraySymbol, newArraySymbol, lowBounds, st->lineNumber()); if (ex != st->expr(i)) st->setExpression(i, ex); } } } static SgStatement* createNewDeclarationStatemnet(SgStatement *loop, SgStatement *originalDeclaration, SgSymbol *arraySymbol) { SgStatement *lastDecl = getFuncStat(loop); while (lastDecl) { if (isSgExecutableStatement(lastDecl)) break; if (lastDecl->variant() == CONTAINS_STMT) break; lastDecl = lastDecl->lexNext(); } SgExpression *exprList = originalDeclaration->expr(0); while (!isEqSymbols(exprList->lhs()->symbol(), arraySymbol)) exprList = exprList->rhs(); checkNull(exprList, convertFileName(__FILE__).c_str(), __LINE__); SgExpression newExprList(EXPR_LIST, exprList->lhs()->copyPtr(), NULL, NULL); SgStatement *newDeclaration = originalDeclaration->copyPtr(); newDeclaration->setExpression(0, newExprList); lastDecl->insertStmtBefore(*newDeclaration, *lastDecl->controlParent()); return newDeclaration; } static SgExpression* constructBoundCall(bool upBound, SgSymbol *array, int dim) { const char *boundName = NULL; upBound ? boundName = "ubound" : boundName = "lbound"; SgSymbol boundS = SgSymbol(FUNCTION_NAME, boundName); SgExpression *dimParam = new SgExpression(EXPR_LIST, new SgValueExp(dim), NULL, NULL); SgExpression params(EXPR_LIST, new SgExpression(ARRAY_REF, NULL, NULL, array), dimParam, NULL); return new SgFunctionCallExp(boundS, params); } static SgExpression* constructReducedAllocation(SgExpression *origArray, SgSymbol *arraySymbol, const vector *indexes) { SgExpression *arrayRef = origArray->copyPtr(); reduceArray(*indexes, arrayRef, arraySymbol); return new SgExpression(EXPR_LIST, arrayRef, (SgExpression*)NULL, (SgSymbol*)NULL); } static SgStatement* getAllocationStmt(const LoopGraph* loop, SgSymbol* symbol) { SgStatement* originalDeclaration = declaratedInStmt(symbol); if (isAllocatable(symbol)) { SgForStmt* loopStmt = (SgForStmt*)(loop->loop->GetOriginal()); SgStatement* allocationStmt = NULL; for (auto& alloc : getAttributes(originalDeclaration, set{ ALLOCATE_STMT })) { if (alloc->variant() != ALLOCATE_STMT) continue; if (findSymbol(symbol, alloc->expr(0)) == NULL) continue; if (allocationStmt == NULL) allocationStmt = alloc; else if (allocationStmt->lineNumber() < alloc->lineNumber() && alloc->lineNumber() < loopStmt->lineNumber()) allocationStmt = alloc; } return allocationStmt; } else return NULL; } static void fillLowBounds(const LoopGraph* forLoop, SgSymbol* origArraySymbol, SgStatement* originalDecl, vector& lowBounds) { SgExpression* origArray = NULL; if (isAllocatable(origArraySymbol)) { SgStatement* allocationStmt = getAllocationStmt(forLoop, origArraySymbol); origArray = findSymbol(origArraySymbol, allocationStmt->expr(0)); } else origArray = findSymbol(origArraySymbol, originalDecl->expr(0)); SgExpression* arrayRef = origArray->copyPtr(); SgExpression* oldTail = arrayRef->lhs(); while (oldTail != NULL) { if (oldTail->lhs()->variant() == DDOT) lowBounds.push_back(oldTail->lhs()->lhs()); else lowBounds.push_back(new SgValueExp(1)); oldTail = oldTail->rhs(); } } static SgExpression* constructArrayAllocationExp(const LoopGraph* forLoop, SgExpression* origArray, SgSymbol* arraySymbol, const vector& indexes, int depthOfResize) { SgExpression *arrayRef = origArray->copyPtr(); arrayRef->setSymbol(arraySymbol); vector dimensions(depthOfResize); SgExpression *oldTail = arrayRef->lhs(); SgSymbol *origArraySymbol = origArray->symbol(); int curDim = 0; while (oldTail != NULL) { curDim++; if (oldTail->lhs()->variant() == DDOT) { SgExpression *ddot = oldTail->lhs(); if (!ddot->lhs()) ddot->setLhs(constructBoundCall(false, origArraySymbol, curDim)); if (!ddot->rhs()) ddot->setRhs(constructBoundCall(true, origArraySymbol, curDim)); } oldTail = oldTail->rhs(); } oldTail = arrayRef->lhs(); SgExpression* newTail = constructArrayRefTailWithLoopBounds(forLoop, depthOfResize, indexes, oldTail); if (arrayRef->variant() == VAR_REF)// create array from scalar { arrayRef = new SgArrayRefExp(*arrayRef->symbol()); arrayRef->setLhs(newTail); } else arrayRef->setLhs(newTail); return new SgExpression(EXPR_LIST, arrayRef, (SgExpression*)NULL, (SgSymbol*)NULL); } static void insertAllocDealloc(const LoopGraph* forLoop, SgSymbol* origArraySymbol, SgSymbol* arraySymbol, SgSymbol* allocDone, bool isExpansion, const vector* indexes = NULL, const vector* shrinkIndexes = NULL) { SgForStmt *loopStmt = (SgForStmt*)(forLoop->loop->GetOriginal()); vector lowBounds; SgStatement *originalDeclaration = declaratedInStmt(origArraySymbol); SgExpression *origArray = NULL; if (isAllocatable(origArraySymbol)) { SgStatement *allocationStmt = getAllocationStmt(forLoop, origArraySymbol); origArray = findSymbol(origArraySymbol, allocationStmt->expr(0)); } else { origArray = findSymbol(origArraySymbol, originalDeclaration->expr(0)); origArray = checkArrayDecl(origArray, origArraySymbol, originalDeclaration); } int depthOfResize = 0; if (isExpansion) for (int i = 0; i < indexes->size(); i++) if ((*indexes)[i] != NULL) depthOfResize++; SgExpression* arrayAllocation = isExpansion ? constructArrayAllocationExp(forLoop, origArray, arraySymbol, *indexes, depthOfResize) : constructReducedAllocation(origArray, arraySymbol, shrinkIndexes); SgExpression *arrayDeallocation = new SgExpression(EXPR_LIST, new SgExpression(ARRAY_REF, (SgExpression*)NULL, (SgExpression*)NULL, arraySymbol), (SgExpression*)NULL, (SgSymbol*)NULL); SgStatement *allocate = new SgStatement(ALLOCATE_STMT, (SgLabel*)NULL, (SgSymbol*)NULL, arrayAllocation, (SgExpression*)NULL, (SgExpression*)NULL); SgIfStmt* ifSt = new SgIfStmt(SgEqOp(*new SgVarRefExp(allocDone), *new SgValueExp(0)), *allocate); loopStmt->insertStmtBefore(*ifSt, *loopStmt->controlParent()); // insert allocates as save //SgStatement* deallocate = new SgStatement(DEALLOCATE_STMT, (SgLabel*)NULL, (SgSymbol*)NULL, arrayDeallocation, (SgExpression*)NULL, (SgExpression*)NULL); //loopStmt->lastNodeOfStmt()->insertStmtAfter(*deallocate, *loopStmt->controlParent()); } static bool containsFunctionCall(SgExpression* exp) { bool retVal = false; if (exp) { if (exp->variant() == FUNC_CALL) retVal = true; if (exp->lhs()) retVal = retVal || containsFunctionCall(exp->lhs()); if (exp->rhs()) retVal = retVal || containsFunctionCall(exp->rhs()); } return retVal; } static SgSymbol* createVarDeclaration(SgForStmt *loopStmt, const char *add) { SgSymbol *doName = loopStmt->doName(); string newNameStr = constructNewBoundName(doName->identifier(), loopStmt->lineNumber(), add); SgSymbol *newName = new SgSymbol(VARIABLE_NAME, newNameStr.c_str(), doName->type(), NULL); SgStatement *decl = declaratedInStmt(doName); SgStatement *newDecl = decl->copyPtr(); newDecl->setExpression(0, new SgExpression(EXPR_LIST, new SgVarRefExp(newName), NULL, NULL)); decl->insertStmtAfter(*newDecl, *decl->controlParent()); return newName; } static SgStatement* createBoundVariableAssign(SgSymbol *varName, SgExpression *value) { SgAssignStmt *assign = new SgAssignStmt(*new SgVarRefExp(varName), *value); return assign; } static void replaceFunctionBounds(SgExpression *ex, SgForStmt *loopStmt, SgForStmt *topLoopStmt, const string &kind) { if (containsFunctionCall(ex)) { SgSymbol *newStart = createVarDeclaration(loopStmt, kind.c_str()); SgStatement *assignment = createBoundVariableAssign(newStart, ex); topLoopStmt->insertStmtBefore(*assignment, *topLoopStmt->controlParent()); if (kind == "_start") loopStmt->setStart(*assignment->expr(0)); if (kind == "_end") loopStmt->setEnd(*assignment->expr(0)); if (kind == "_step") loopStmt->setStep(*assignment->expr(0)); } } static void replaceFunctionBounds(const LoopGraph *forLoop, int depthOfResize) { const LoopGraph *curLoop = forLoop; SgForStmt *topLoopStmt = (SgForStmt*) (curLoop->loop->GetOriginal()); for (int i = 0; i < depthOfResize; ++i) { SgForStmt *loopStmt = (SgForStmt*) (curLoop->loop->GetOriginal()); replaceFunctionBounds(loopStmt->start(), loopStmt, topLoopStmt, "_start"); replaceFunctionBounds(loopStmt->end(), loopStmt, topLoopStmt, "_end"); replaceFunctionBounds(loopStmt->step(), loopStmt, topLoopStmt, "_step"); if (i + 1 != depthOfResize) curLoop = curLoop->children[0]; } } static SgSymbol* createReducedToVariableArray(SgStatement *copiedDeclaration, int lineNumber, SgSymbol *arraySymbol) { SgType *type = copiedDeclaration->expr(1)->type(); string newNameStr = constructNewBoundName(arraySymbol->identifier(), lineNumber, "_sh"); SgSymbol *newName = new SgSymbol(VARIABLE_NAME, newNameStr.c_str(), type, NULL); copiedDeclaration->setExpression(0, new SgExpression(EXPR_LIST, new SgVarRefExp(newName), NULL, NULL)); return newName; } static void reduceArrayRefsInExpr(SgExpression *expr, SgSymbol *arraySymbol, SgSymbol *newSymbol, bool reduceToVariable, vector &indexes) { if (expr == NULL) return; SgExpression *lhs = expr->lhs(), *rhs = expr->rhs(); if (lhs) { if (isArrayRef(lhs) && isEqSymbols(arraySymbol, lhs->symbol())) { if (reduceToVariable) expr->setLhs(new SgVarRefExp(newSymbol)); else reduceArray(indexes, lhs, newSymbol); } else reduceArrayRefsInExpr(lhs, arraySymbol, newSymbol, reduceToVariable, indexes); } if (rhs) { if (isArrayRef(rhs) && isEqSymbols(arraySymbol, rhs->symbol())) { if (reduceToVariable) expr->setRhs(new SgVarRefExp(newSymbol)); else reduceArray(indexes, rhs, newSymbol); } else reduceArrayRefsInExpr(rhs, arraySymbol, newSymbol, reduceToVariable, indexes); } } static void reduceArrayRefs(SgStatement *st, SgSymbol *arraySymbol, SgSymbol *newSymbol, bool reduceToVariable, vector &indexes) { for (int i = 0; i < 3; ++i) { if (st->expr(i)) { SgExpression* expr = st->expr(i); if (isArrayRef(expr) && isEqSymbols(arraySymbol, expr->symbol())) { if (reduceToVariable) st->setExpression(i, new SgVarRefExp(newSymbol)); else reduceArray(indexes, expr, newSymbol); } else reduceArrayRefsInExpr(expr, arraySymbol, newSymbol, reduceToVariable, indexes); } } } static void fillIndexesToShrink(SgSymbol* arr, SgExprListExp* listExp, vector& indexes) { SgExpression* sym = findSymbol(arr, listExp); if (sym) { SgExpression* expr = sym->lhs(); while (expr) { indexes.push_back(expr->lhs()->valueInteger()); expr = expr->rhs(); } bool needShrink = false; for (int z = 0; z < indexes.size(); ++z) if (indexes[z] == 1) needShrink = true; if (!needShrink) indexes.clear(); } } static void renamePrivateVarsInAttributes(const vector& attrs, const map& symbols) { for (SgStatement* st : attrs) { if (st->variant() != SPF_ANALYSIS_DIR) return; SgExpression* exprList = st->expr(0); while (exprList) { if (exprList->lhs()->variant() == ACC_PRIVATE_OP) { SgExpression* list = exprList->lhs()->lhs(); while (list) { for (auto& pair : symbols) if (isEqSymbols(pair.first, list->lhs()->symbol())) list->setLhs(new SgExpression(ARRAY_REF, NULL, NULL, pair.second)); list = list->rhs(); } } exprList = exprList->rhs(); } } } static void removePrivateVarsInAttributes(const vector& attrs, const map& symbols) { for (SgStatement* st : attrs) { if (st->variant() != SPF_ANALYSIS_DIR) return; SgExpression* exprList = st->expr(0); vector newL; bool remList = false; while (exprList) { if (exprList->lhs()->variant() == ACC_PRIVATE_OP) { vector newL; bool removed = false; SgExpression* list = exprList->lhs()->lhs(); while (list) { bool found = false; for (auto& pair : symbols) { if (isEqSymbols(pair.first, list->lhs()->symbol())) found = true; if (found) break; } if (!found) newL.push_back(list->lhs()); else removed = true; list = list->rhs(); } if (removed) { if (newL.size() == 0) remList = true; else { exprList->lhs()->setLhs(makeExprList(newL)); newL.push_back(exprList->lhs()); } } } else newL.push_back(exprList->lhs()); exprList = exprList->rhs(); } if (remList) st->setExpression(0, makeExprList(newL)); } } static int getArrayDimensionality(SgSymbol* array) { if (array->type()->variant() != T_ARRAY) return 0; SgStatement* decl = declaratedInStmt(array); DIST::Array* currArray = getArrayFromDeclarated(decl, array->identifier()); checkNull(currArray, convertFileName(__FILE__).c_str(), __LINE__); return currArray->GetDimSize(); } static bool isWellDistributedArray(const LoopGraph* loop, const DIST::Array* array, int depthOfResize, bool fromWrite) { const LoopGraph* curLoop = loop; bool found = true; const vector* arrayOps = NULL; for (int i = 0; i < depthOfResize; i++) { if (fromWrite) { for (auto& writeOp : curLoop->writeOps) { if (isEqSymbols(writeOp.first->GetDeclSymbol(), array->GetDeclSymbol())) { arrayOps = &writeOp.second; break; } } } else { for (auto& readOp : curLoop->readOps) { if (isEqSymbols(readOp.first->GetDeclSymbol(), array->GetDeclSymbol())) { arrayOps = &readOp.second.first; break; } } } if (arrayOps == NULL) return false; int counter = 0; for (int j = 0; j < arrayOps->size(); j++) { if (!(*arrayOps)[j].coefficients.empty()) counter++; for (const auto& elem : (*arrayOps)[j].coefficients) { if (elem.first.first != 1 || elem.first.second != 0) { found = false; break; } } } if (counter != 1) found = false; if (!found) break; if (i != depthOfResize - 1) curLoop = curLoop->children[0]; } if (found) return true; return false; } static SgSymbol* findDistributedArrayWrite(const LoopGraph* loop, int origDim, int depthOfResize) { for (auto& writeOp : loop->writeOps) { if (writeOp.second.size() != (size_t)origDim + depthOfResize) continue; if (isWellDistributedArray(loop, writeOp.first, depthOfResize, true)) return writeOp.first->GetDeclSymbol(); } return NULL; } static SgSymbol* findDistributedArrayRead(const LoopGraph* loop, int origDim, int depthOfResize) { for (auto& readOp : loop->readOps) { if (readOp.second.first.size() != (size_t)origDim + depthOfResize) continue; if (isWellDistributedArray(loop, readOp.first, depthOfResize, false)) return readOp.first->GetDeclSymbol(); } return NULL; } static void mapIndexes(const LoopGraph* loop, int depthOfResize, SgSymbol* distributedArray, vector& indexes, bool fromWrite) { int dim = getArrayDimensionality(distributedArray); vector mapped(dim); for (int i = 0; i < dim; i++) mapped[i] = false; const LoopGraph* curLoop = loop; int deep = depthOfResize; for (int i = 0; i < deep - 1; i++) curLoop = curLoop->children[0]; const vector* arrayOps = NULL; for (int i = 0; i < deep; i++) { if (fromWrite) { for (auto& writeOp : curLoop->writeOps) { if (isEqSymbols(writeOp.first->GetDeclSymbol(), distributedArray)) { arrayOps = &writeOp.second; break; } } } else { for (auto& readOp : curLoop->readOps) { if (isEqSymbols(readOp.first->GetDeclSymbol(), distributedArray)) { arrayOps = &readOp.second.first; break; } } } if (arrayOps == NULL) { printInternalError(convertFileName(__FILE__).c_str(), __LINE__); return; } for (int j = 0; j < dim; j++) { if (!(*arrayOps)[j].coefficients.empty()) { if (i == 0 && deep == depthOfResize + 1) mapped[j] = true; else { if (!mapped[j]) { indexes[j] = ((SgForStmt*)curLoop->loop->GetOriginal())->doName(); mapped[j] = true; } } } } if (i != deep - 1) curLoop = curLoop->parent; } } static int fillIndexesToExtend(const LoopGraph* loop, int origDim, int depthOfResize, vector& indexes) { SgSymbol* distributedArray = NULL; distributedArray = findDistributedArrayWrite(loop, origDim, depthOfResize); bool fromWrite = true; if (distributedArray == NULL) { distributedArray = findDistributedArrayRead(loop, origDim, depthOfResize); fromWrite = false; } if (distributedArray == NULL) return -1; mapIndexes(loop, depthOfResize, distributedArray, indexes, fromWrite); return 0; } static SgSymbol* shrinkArray(const LoopGraph *forLoop, SgSymbol *arraySymbol, vector &indexes, SgSymbol *allocDone) { int maxDepth = forLoop->perfectLoop; const LoopGraph *curLoop = forLoop; bool reduceToVariable = true; for (int i = 0; i < indexes.size(); ++i) { if (indexes[i] == 0) { reduceToVariable = false; break; } } for (int i = 0; i < maxDepth; ++i) { if (curLoop->children.size() == 1) curLoop = curLoop->children[0]; else if (i != maxDepth - 1) { printInternalError(convertFileName(__FILE__).c_str(), __LINE__); return NULL; } } replaceFunctionBounds(forLoop, maxDepth); SgStatement *originalDeclaration = declaratedInStmt(arraySymbol); SgStatement *copiedDeclaration = createNewDeclarationStatemnet(forLoop->loop->GetOriginal(), originalDeclaration, arraySymbol); bool canBeStatic = !(!reduceToVariable && isAllocatable(arraySymbol)); SgSymbol *newSymbol = reduceToVariable ? createReducedToVariableArray(copiedDeclaration, forLoop->lineNum, arraySymbol) : alterShrinkArrayDeclaration(copiedDeclaration, arraySymbol, indexes, canBeStatic); if (newSymbol) { SgForStmt *loopStmt = (SgForStmt*)(forLoop->loop->GetOriginal()); if (!reduceToVariable && isAllocatable(arraySymbol)) insertAllocDealloc(forLoop, arraySymbol, newSymbol, allocDone, false, NULL, &indexes); for (SgStatement *st = loopStmt->lexNext(); st != loopStmt->lastNodeOfStmt()->lexNext(); st = st->lexNext()) if (st->variant() != ALLOCATE_STMT && st->variant() != DEALLOCATE_STMT) reduceArrayRefs(st, arraySymbol, newSymbol, reduceToVariable, indexes); return newSymbol; } return NULL; } static SgSymbol* resizeArray(const LoopGraph *forLoop, SgSymbol *arraySymbol, int depthOfResize, SgSymbol *allocDone) { if (depthOfResize < 0 || depthOfResize > forLoop->perfectLoop) depthOfResize = forLoop->perfectLoop; int arrayDim = getArrayDimensionality(arraySymbol); vector indexes((size_t)depthOfResize + arrayDim); int areIndexesFilled = fillIndexesToExtend(forLoop, arrayDim, depthOfResize, indexes); const LoopGraph* curLoop = forLoop; bool canBeStatic = true; if (isAllocatable(arraySymbol)) canBeStatic = false; for (int i = 0; i < depthOfResize; ++i) { //TODO: add checking for PARAMETER //if (curLoop->calculatedCountOfIters == 0) canBeStatic = false; if (areIndexesFilled != 0) { SgForStmt* loopStmt = (SgForStmt*)curLoop->loop->GetOriginal(); indexes[(size_t)depthOfResize + arrayDim - 1 - i] = loopStmt->doName(); } if (curLoop->children.size() == 1) curLoop = curLoop->children[0]; else if (i != depthOfResize - 1) { printInternalError(convertFileName(__FILE__).c_str(), __LINE__); return NULL; } } replaceFunctionBounds(forLoop, depthOfResize); SgStatement* originalDeclaration = declaratedInStmt(arraySymbol); SgStatement *copiedOriginalDecl = createNewDeclarationStatemnet(forLoop->loop->GetOriginal(), originalDeclaration, arraySymbol); SgSymbol *newArraySymbol = alterExtendArrayDeclaration(forLoop, copiedOriginalDecl, arraySymbol, canBeStatic, indexes); vector lowBounds(depthOfResize); fillLowBounds(forLoop, arraySymbol, originalDeclaration, lowBounds); if (newArraySymbol) { SgForStmt *loopStmt = (SgForStmt*)(forLoop->loop->GetOriginal()); if (!canBeStatic || isAllocatable(newArraySymbol)) insertAllocDealloc(forLoop, arraySymbol, newArraySymbol, allocDone, true, &indexes, NULL); for (SgStatement *st = loopStmt->lexNext(); st != loopStmt->lastNodeOfStmt()->lexNext(); st = st->lexNext()) if (st->variant() != ALLOCATE_STMT && st->variant() != DEALLOCATE_STMT) extendArrayRefs(indexes, st, arraySymbol, newArraySymbol, lowBounds); return newArraySymbol; } return NULL; } //for testing static SgSymbol* findSymbol(LoopGraph *forLoop, const char *arrayName) { SgForStmt *loopStmt = (SgForStmt*)forLoop->loop->GetOriginal(); if (loopStmt) { for (SgStatement *st = loopStmt->lexNext(); st != loopStmt->lastNodeOfStmt()->lexNext(); st = st->lexNext()) { queue toCheck = queue(); for (int i = 0; i < 3; ++i) if (st->expr(i)) toCheck.push(st->expr(i)); while (!toCheck.empty()) { SgExpression *curExp = toCheck.front(); toCheck.pop(); if ((isArrayRef(curExp) || curExp->variant() == VAR_REF) && !strcmp(arrayName, curExp->symbol()->identifier())) return curExp->symbol(); else { if (curExp->lhs()) toCheck.push(curExp->lhs()); if (curExp->rhs()) toCheck.push(curExp->rhs()); } } } } return NULL; } static set fillPrivates(const map, set>& usersDirectives, LoopGraph *loop) { set attrsPriv; auto itPriv = usersDirectives.find(make_pair(loop->loop->fileName(), loop->loop->lineNumber())); if (itPriv != usersDirectives.end()) attrsPriv = itPriv->second; set privates; for (auto& spf : attrsPriv) if (spf->variant() == SPF_ANALYSIS_DIR) fillPrivatesFromComment(new Statement(spf), privates); set arrayPrivates; set iterationVars; fillIterationVariables(loop, iterationVars); for (Symbol* sym : privates) if (sym->variant() == VARIABLE_NAME) if (iterationVars.find(sym->identifier()) == iterationVars.end()) arrayPrivates.insert(sym->GetOriginal()); return arrayPrivates; } static map> doNotShrink; static void analyzeExpr(SgExpression* ex, const string& arr, const vector& indexes, vector& exprs, int& err) { if (ex && err == 0) { if (ex->variant() == ARRAY_REF && ex->symbol()->identifier() == arr) { SgArrayRefExp* ref = isSgArrayRefExp(ex); if (ex == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (ref->numberOfSubscripts() == 0) err = 1; else { if (ref->numberOfSubscripts() != exprs.size()) err = 2; else { for (int z = 0; z < indexes.size(); z++) { if (indexes[z] == 1) { string cur = ref->subscript(z)->unparse(); if (exprs[z] == "") exprs[z] = cur; else if (exprs[z] != cur) { err = 3; return; } } } } } } else { analyzeExpr(ex->lhs(), arr, indexes, exprs, err); analyzeExpr(ex->rhs(), arr, indexes, exprs, err); } } } static bool isNeedSkip(SgStatement* start, const string& arr, const vector& indexes) { vector exprs(indexes.size()); for (int z = 0; z < indexes.size(); ++z) exprs[z] = ""; for (auto st = start; st != start->lastNodeOfStmt(); st = st->lexNext()) { int err = 0; for (int z = 0; z < 3; ++z) { analyzeExpr(st->expr(z), arr, indexes, exprs, err); if (err != 0) return true; } } return false; } //TODO: need to add messages void analyzeShrinking(SgFile* file, const vector& loopGraphs, vector& messages, const map, set>& usersDirectives) { map mapLoopGraph; createMapLoopGraph(loopGraphs, mapLoopGraph); for (auto& loopPair : mapLoopGraph) { LoopGraph* loop = loopPair.second; auto loopSt = loop->loop->GetOriginal(); auto attrsTr = getAttributes(loopSt, set{ SPF_TRANSFORM_DIR }); auto attrPrivInCode = getAttributes(loopSt, set{ SPF_ANALYSIS_DIR }); auto arrayPrivates = fillPrivates(usersDirectives, loop); if (arrayPrivates.size() != 0) { for (auto attr : attrsTr) { SgExpression* list = attr->expr(0); while (list) { if (list->lhs()->variant() == SPF_SHRINK_OP) { SgExprListExp* listExp = isSgExprListExp(list->lhs()->lhs()); checkNull(listExp, convertFileName(__FILE__).c_str(), __LINE__); for (SgSymbol* privArr : arrayPrivates) { vector indexes; fillIndexesToShrink(privArr, listExp, indexes); if (!indexes.empty()) { string array = privArr->identifier(); if (isNeedSkip(loop->loop, array, indexes)) doNotShrink[loop].insert(array); } } } list = list->rhs(); } } } } } static void createAllocDoneSymbol(map& allocDoneByFunc, SgStatement* func) { if (allocDoneByFunc.find(func) == allocDoneByFunc.end()) { auto newName = (string("spf_") + string(func->symbol()->identifier()) + "_alloc_"); allocDoneByFunc[func] = new SgSymbol(VARIABLE_NAME, newName.c_str(), SgTypeInt(), func); } } //Вычислять размер массива с учётом шага цикла - //TODO void privateArraysResizing(SgFile *file, const vector &loopGraphs, vector &messages, int& countOfTransform, const map, set>& usersDirectives, bool isExpand) { map mapLoopGraph; createMapLoopGraph(loopGraphs, mapLoopGraph); map allocDoneByFunc; map usedAllocDoneByFunc; map> saveDecls; for (auto &loopPair : mapLoopGraph) { LoopGraph *loop = loopPair.second; auto itSh = doNotShrink.find(loop); auto loopSt = loop->loop->GetOriginal(); auto attrsTr = getAttributes(loopSt, set{ SPF_TRANSFORM_DIR }); auto attrPrivInCode = getAttributes(loopSt, set{ SPF_ANALYSIS_DIR }); auto arrayPrivates = fillPrivates(usersDirectives, loop); auto func = getFuncStat(loopSt); set symbolsToDecl; if (arrayPrivates.size() == 0) { string str; if (isExpand) __spf_printToBuf(str, "Can not do PRIVATE EXPANSION for this loop - privates not found"); else __spf_printToBuf(str, "Can not do PRIVATE SHRINK for this loop - privates not found"); __spf_print(0, "%s on line %d\n", str.c_str(), loop->lineNum); } else { for (auto attr : attrsTr) { SgExpression *list = attr->expr(0); vector newL; map symbols; while (list) { symbols.clear(); if (list->lhs()->variant() == SPF_EXPAND_OP && isExpand) { createAllocDoneSymbol(allocDoneByFunc, func); int deep = -1; if (list->lhs()->lhs() != NULL) { SgExprListExp* listExp = isSgExprListExp(list->lhs()->lhs()); checkNull(listExp, convertFileName(__FILE__).c_str(), __LINE__); deep = listExp->length(); } for (SgSymbol* privArr : arrayPrivates) { SgSymbol* newSymbol = resizeArray(loop, privArr, deep, allocDoneByFunc[func]); if (newSymbol) { symbols.insert(std::make_pair(privArr, newSymbol)); usedAllocDoneByFunc[func] = allocDoneByFunc[func]; countOfTransform++; if (isAllocatable(newSymbol)) symbolsToDecl.insert(newSymbol); } } removePrivateVarsInAttributes(attrPrivInCode, symbols); } else if (list->lhs()->variant() == SPF_SHRINK_OP && !isExpand) { createAllocDoneSymbol(allocDoneByFunc, func); SgExprListExp* listExp = isSgExprListExp(list->lhs()->lhs()); checkNull(listExp, convertFileName(__FILE__).c_str(), __LINE__); for (SgSymbol* privArr : arrayPrivates) { vector indexes; fillIndexesToShrink(privArr, listExp, indexes); bool skip = false; if (itSh != doNotShrink.end()) if (itSh->second.find(privArr->identifier()) != itSh->second.end()) skip = true; if (!indexes.empty() && !skip) { SgSymbol* newSymbol = shrinkArray(loop, privArr, indexes, allocDoneByFunc[func]); if (newSymbol) { symbols.insert(std::make_pair(privArr, newSymbol)); usedAllocDoneByFunc[func] = allocDoneByFunc[func]; countOfTransform++; if (isAllocatable(newSymbol)) symbolsToDecl.insert(newSymbol); } } } renamePrivateVarsInAttributes(attrPrivInCode, symbols); } else newL.push_back(list); list = list->rhs(); } attr->setExpression(0, makeExprList(newL, false)); //__spf_print(1, "set new %d attributes to line %d\n", newL.size(), loop->lineNum); } } for (auto& elem : symbolsToDecl) saveDecls[func].push_back(new SgVarRefExp(elem)); } for (auto& funcPair : saveDecls) { auto func = funcPair.first; if (usedAllocDoneByFunc.find(func) == usedAllocDoneByFunc.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); SgSymbol* allocVar = usedAllocDoneByFunc[func]; auto list = makeExprList(funcPair.second); SgStatement* save = new SgStatement(SAVE_DECL, NULL, NULL, list); SgStatement* st = func->lexNext(); while (!isSgExecutableStatement(st)) { if (st->variant() == CONTAINS_STMT) break; st = st->lexNext(); } vector init = { new SgValueExp(-1) }; makeDeclaration(func, { allocVar }, &init); st->insertStmtBefore(*save, *func); SgAssignStmt* assign = new SgAssignStmt(*new SgVarRefExp(allocVar), *new SgVarRefExp(allocVar) + *new SgValueExp(1)); st->insertStmtBefore(*assign, *func); } }