#include #include #include #include #include #include #include #include #include "private_arrays_search.h" #include "range_structures.h" #include "region.h" #include "SgUtils.h" #include "graph_loops.h" #include "CFGraph/CFGraph.h" #include "utils.h" using namespace std; static unordered_set collapsed; static void RemoveEmptyPoints(ArrayAccessingIndexes& container) { ArrayAccessingIndexes resultContainer; unordered_set toRemove; for (auto& [arrayName, accessingSet] : container) { vector> points; for (auto& arrayPoint : accessingSet.GetElements()) { if (!arrayPoint.empty()) points.push_back(arrayPoint); } if (points.size() < accessingSet.GetElements().size() && !points.empty()) resultContainer[arrayName] = points; if (points.empty()) toRemove.insert(arrayName); } for (const string& name : toRemove) container.erase(name); for (auto& [arrayName, accessingSet] : resultContainer) container[arrayName] = accessingSet; } static void Collapse(Region* region) { if (region->getBasickBlocks().empty()) return; bool firstRegion = true; for (Region* basickBlock : region->getBasickBlocks()) { if (basickBlock->getNextRegions().empty()) { if (firstRegion) { region->array_def = basickBlock->array_out; firstRegion = false; } else { unordered_set toErease; for (auto& [arrayName, arrayRanges] : region->array_def) { if (basickBlock->array_out.find(arrayName) != basickBlock->array_out.end()) arrayRanges = arrayRanges.Intersect(basickBlock->array_out[arrayName]); else { arrayRanges = AccessingSet(); toErease.insert(arrayName); } } for (string arrayName : toErease) region->array_def.erase(arrayName); } } } RegionInstruction instruction; instruction.def = move(region->array_def); for (auto& byBlock : region->getBasickBlocks()) { for (auto& instruction : byBlock->instructions) { for (auto& [arrayName, _] : instruction.use) { AccessingSet diff = instruction.use[arrayName].Diff(instruction.in[arrayName]); region->array_use[arrayName] = region->array_use[arrayName].Union(diff); } } } ArrayAccessingIndexes useUnionB; for (auto& byBlock : region->getBasickBlocks()) for (auto& instruction : byBlock->instructions) for (auto& [arrayName, _] : instruction.use) useUnionB[arrayName] = useUnionB[arrayName].Union(instruction.use[arrayName]); for (auto& [arrayName, _] : useUnionB) region->array_priv[arrayName] = useUnionB[arrayName].Diff(region->array_use[arrayName]); instruction.use = move(region->array_use); for (Region* prevBlock : region->getHeader()->getPrevRegions()) { prevBlock->replaceInNextRegions(region, region->getHeader()); region->addPrevRegion(prevBlock); } for (Region* nextBlock : region->getHeader()->getNextRegions()) { nextBlock->replaceInPrevRegions(region, region->getHeader()); region->addNextRegion(nextBlock); } region->instructions.push_back(instruction); } static void SolveDataFlowIteratively(Region* DFG) { auto blocks = DFG->getBasickBlocks(); std::unordered_set worklist(blocks.begin(), blocks.end()); do { Region* b = *worklist.begin(); ArrayAccessingIndexes newIn; bool flagFirst = true; for (Region* prevBlock : b->getPrevRegions()) { if (flagFirst) { newIn = prevBlock->array_out; flagFirst = false; } else { if (prevBlock->array_out.empty()) { newIn.clear(); break; } for (const auto& [arrayName, accessSet] : prevBlock->array_out) { if (newIn.find(arrayName) != newIn.end()) newIn[arrayName] = newIn[arrayName].Intersect(accessSet); else newIn[arrayName] = AccessingSet(); } } } b->array_in = move(newIn); ArrayAccessingIndexes newOut; if (b->array_def.empty()) newOut = b->array_in; else if (b->array_in.empty()) newOut = b->array_def; else { for (auto& [arrayName, accessSet] : b->array_def) { if (newOut.find(arrayName) != newOut.end()) newOut[arrayName] = b->array_def[arrayName].Union(b->array_in[arrayName]); else newOut[arrayName] = accessSet; } } /* can not differ */ if (newOut != b->array_out) b->array_out = newOut; else worklist.erase(b); } while (!worklist.empty()); } static void SolveForBasickBlock(Region* block) { ArrayAccessingIndexes newIn; bool flagFirst = true; for (Region* prevBlock : block->getPrevRegions()) { if (flagFirst) { newIn = prevBlock->array_out; flagFirst = false; } else { if (prevBlock->array_out.empty()) { newIn.clear(); break; } for (const auto& [arrayName, accessSet] : prevBlock->array_out) { if (newIn.find(arrayName) != newIn.end()) newIn[arrayName] = newIn[arrayName].Intersect(accessSet); else newIn[arrayName] = AccessingSet(); } } } if (block->instructions.empty()) block->instructions.push_back(RegionInstruction()); block->instructions[0].in = move(newIn); for (int i = 0; i < block->instructions.size(); i++) { auto& instruction = block->instructions[i]; if (i > 0) instruction.in = block->instructions[i - 1].out; ArrayAccessingIndexes newOut; if (instruction.def.empty()) newOut = instruction.in; else if (instruction.in.empty()) newOut = instruction.def; else { for (auto& [arrayName, accessSet] : instruction.def) { if (instruction.in.find(arrayName) != instruction.in.end()) newOut[arrayName] = instruction.def[arrayName].Union(instruction.in[arrayName]); else newOut[arrayName] = accessSet; } for (auto& [arrayName, accessSet] : instruction.in) { if (newOut.find(arrayName) == newOut.end()) { newOut[arrayName] = accessSet; } } } instruction.out = move(newOut); } if (!block->instructions.empty()) block->array_out = block->instructions.back().out; } static void SolveDataFlowTopologically(Region* DFG) { for (Region* b : DFG->getBasickBlocks()) { collapsed.insert(b); SolveForBasickBlock(b); } } static void SolveDataFlow(Region* DFG) { if (!DFG) return; for (Region* subRegion : DFG->getSubRegions()) { SolveDataFlow(subRegion); DFG->addBasickBlocks(subRegion); } vector& blocks = DFG->getBasickBlocks(); auto pos = remove_if(blocks.begin(), blocks.end(), [](Region* r) { return collapsed.find(r) != collapsed.end(); }); blocks.erase(pos, blocks.end()); TopologySort(DFG->getBasickBlocks(), DFG->getHeader()); SolveDataFlowTopologically(DFG); Collapse(DFG); } static bool getArrayDeclaredDimensions(SgArrayRefExp* arrayRef, vector& declaredDims) { declaredDims.clear(); if (!arrayRef || !arrayRef->symbol() || !isSgArrayType(arrayRef->symbol()->type())) return false; SgArrayType* arrayType = (SgArrayType*)arrayRef->symbol()->type(); int dimCount = arrayType->dimension(); for (int i = 0; i < dimCount; i++) { SgExpression* sizeExpr = arrayType->sizeInDim(i); SgConstantSymb* constValSymb = isSgConstantSymb(sizeExpr->symbol()); string strDimLength; if (sizeExpr && sizeExpr->variant() == INT_VAL) strDimLength = sizeExpr->unparse(); else if (constValSymb) strDimLength = constValSymb->constantValue()->unparse(); else return false; if (strDimLength == "0") return false; declaredDims.push_back((uint64_t)stoi(strDimLength)); } return true; } static bool CheckDimensionLength(const AccessingSet& array) { if (array.GetElements().empty()) return false; size_t dimCount = array.GetElements()[0].size(); SgArrayRefExp* arrayRef = array.GetElements()[0][0].array; if (!arrayRef) return false; vector declaredDims(dimCount); if (!getArrayDeclaredDimensions(arrayRef, declaredDims)) return false; vector testArray(dimCount); for (size_t i = 0; i < dimCount; i++) { testArray[i] = { 1, 1, declaredDims[i], nullptr }; } AccessingSet diff = AccessingSet({ testArray }).Diff(array); return diff.GetElements().empty(); } static void AddPrivateArraysToLoop(LoopGraph* loop, const ArrayAccessingIndexes& privates, set& insertedPrivates) { SgStatement* spfStat = new SgStatement(SPF_ANALYSIS_DIR); spfStat->setlineNumber(loop->loop->lineNumber()); spfStat->setFileName(loop->loop->fileName()); SgExpression* toAdd = new SgExpression(EXPR_LIST, new SgExpression(ACC_PRIVATE_OP), NULL, NULL); set arraysToInsert; for (const auto& [_, accessingSet] : privates) { if (!CheckDimensionLength(accessingSet)) continue; for (const auto& arrayElement : accessingSet.GetElements()) { if (arrayElement.empty()) continue; arraysToInsert.insert(arrayElement[0].array->symbol()); } } spfStat->setExpression(0, *toAdd); toAdd = toAdd->lhs(); bool first = true; for (auto& elem : arraysToInsert) { if (first) { toAdd->setLhs(new SgExpression(EXPR_LIST)); toAdd = toAdd->lhs(); first = false; } else { toAdd->setRhs(new SgExpression(EXPR_LIST)); toAdd = toAdd->rhs(); } toAdd->setLhs(new SgVarRefExp(elem)); } if (arraysToInsert.size() != 0) { loop->loop->insertStmtBefore(*spfStat, *loop->loop->controlParent()); insertedPrivates.insert(spfStat); } } void FindPrivateArrays(map>& loopGraph, map>& FullIR, set& insertedPrivates) { map result; for (const auto& [fileName, loops] : loopGraph) { SgFile::switchToFile(fileName); for (const auto& loop : loops) { if (!loop->isFor()) continue; SgStatement* search_func = loop->loop->GetOriginal(); while (search_func && (!isSgProgHedrStmt(search_func))) search_func = search_func->controlParent(); for (const auto& [funcInfo, blocks] : FullIR) { if (funcInfo->fileName == fileName && funcInfo->funcPointer->GetOriginal() == search_func) { Region* loopRegion = new Region(loop, blocks); if (loopRegion->getBasickBlocks().size() <= 1) { delete(loopRegion); continue; } SolveDataFlow(loopRegion); RemoveEmptyPoints(loopRegion->array_priv); result[loop] = loopRegion->array_priv; delete(loopRegion); } } if (result.find(loop) != result.end() && !result[loop].empty()) AddPrivateArraysToLoop(loop, result[loop], insertedPrivates); } } }