diff --git a/include/tsar/Support/Directives.td b/include/tsar/Support/Directives.td index f0e2024e..11917363 100644 --- a/include/tsar/Support/Directives.td +++ b/include/tsar/Support/Directives.td @@ -139,6 +139,10 @@ def Rename : Clause<"rename", Transform>; def LoopInterchange : Clause<"interchange", Transform, [LParen, PPIdentifier, Comma, PPIdentifier, RParen]>; +def RemoveRedarray : Clause<"remove_redarray", Transform, + [LParen, Identifier, LSquare, NumericConstant, RSquare, + ZeroOrMore<[Comma, Identifier, LSquare, NumericConstant, RSquare]>, RParen]>; + def Replace : Clause<"replace", Transform, [ZeroOrOne<[LParen, Identifier, ZeroOrMore<[Comma, Identifier]>, RParen]>]>; diff --git a/include/tsar/Transform/Clang/Passes.h b/include/tsar/Transform/Clang/Passes.h index dcb9dc5f..5ff7bf86 100644 --- a/include/tsar/Transform/Clang/Passes.h +++ b/include/tsar/Transform/Clang/Passes.h @@ -112,6 +112,8 @@ void initializeClangLoopInterchangePass(PassRegistry &Registry); /// Initialize a pass to reverse loop. void initializeClangLoopReversePass(PassRegistry &Registry); +void initializeClangRemoveRedarrayPass(PassRegistry &Registry); + /// Create a pass to reverse loop. ModulePass *createClangLoopReverse(); } diff --git a/lib/Transform/Clang/CMakeLists.txt b/lib/Transform/Clang/CMakeLists.txt index d5eef742..9b46d4d1 100644 --- a/lib/Transform/Clang/CMakeLists.txt +++ b/lib/Transform/Clang/CMakeLists.txt @@ -2,7 +2,8 @@ set(TRANSFORM_SOURCES Passes.cpp ExprPropagation.cpp Inline.cpp RenameLocal.cpp DeadDeclsElimination.cpp Format.cpp OpenMPAutoPar.cpp DVMHWriter.cpp SharedMemoryAutoPar.cpp DVMHDirecitves.cpp DVMHSMAutoPar.cpp DVMHDataTransferIPO.cpp StructureReplacement.cpp LoopInterchange.cpp - LoopReversal.cpp) + LoopReversal.cpp RemoveRedarray.cpp) + if(MSVC_IDE) file(GLOB_RECURSE TRANSFORM_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/lib/Transform/Clang/Passes.cpp b/lib/Transform/Clang/Passes.cpp index 1414a706..780428db 100644 --- a/lib/Transform/Clang/Passes.cpp +++ b/lib/Transform/Clang/Passes.cpp @@ -38,5 +38,6 @@ void llvm::initializeClangTransform(PassRegistry &Registry) { initializeClangDVMHSMParallelizationPass(Registry); initializeDVMHDataTransferIPOPassPass(Registry); initializeClangLoopInterchangePass(Registry); + initializeClangRemoveRedarrayPass(Registry); initializeClangLoopReversePass(Registry); } diff --git a/lib/Transform/Clang/RemoveRedarray.cpp b/lib/Transform/Clang/RemoveRedarray.cpp new file mode 100644 index 00000000..5d9b3c91 --- /dev/null +++ b/lib/Transform/Clang/RemoveRedarray.cpp @@ -0,0 +1,583 @@ +//===--- LoopInterchange.cpp - Loop Interchagne (Clang) ---------*- C++ -*-===// +// +// Traits Static Analyzer (SAPFOR) +// +// Copyright 2021 DVM System Group +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements a pass to perform remove redarray in C programs. +// +//===----------------------------------------------------------------------===// + +#include "tsar/ADT/SpanningTreeRelation.h" +#include "tsar/Analysis/AnalysisServer.h" +#include "tsar/Analysis/Clang/CanonicalLoop.h" +#include "tsar/Analysis/Clang/DIMemoryMatcher.h" +#include "tsar/Analysis/Clang/GlobalInfoExtractor.h" +#include "tsar/Analysis/Clang/MemoryMatcher.h" +#include "tsar/Analysis/Clang/NoMacroAssert.h" +#include "tsar/Analysis/Clang/PerfectLoop.h" +#include "tsar/Analysis/DFRegionInfo.h" +#include "tsar/Analysis/Memory/ClonedDIMemoryMatcher.h" +#include "tsar/Analysis/Memory/DIClientServerInfo.h" +#include "tsar/Analysis/Memory/DIDependencyAnalysis.h" +#include "tsar/Analysis/Memory/DIEstimateMemory.h" +#include "tsar/Analysis/Memory/DIMemoryTrait.h" +#include "tsar/Analysis/Memory/EstimateMemory.h" +#include "tsar/Analysis/Memory/MemoryAccessUtils.h" +#include "tsar/Analysis/Memory/MemoryTraitUtils.h" +#include "tsar/Analysis/Memory/Passes.h" +#include "tsar/Analysis/Memory/Utils.h" +#include "tsar/Core/Query.h" +#include "tsar/Frontend/Clang/Pragma.h" +#include "tsar/Frontend/Clang/TransformationContext.h" +#include "tsar/Support/Clang/Diagnostic.h" +#include "tsar/Support/GlobalOptions.h" +#include "tsar/Support/MetadataUtils.h" +#include "tsar/Transform/Clang/Passes.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace tsar; + +#undef DEBUG_TYPE +#define DEBUG_TYPE "clang-remove-redarray" +#define DEBUG_PREFIX "[REMOVE REDARRAY]: " + + +namespace { +class ClangRemoveRedarray : public FunctionPass, private bcl::Uncopyable { +public: + static char ID; + + ClangRemoveRedarray() : FunctionPass(ID) { + initializeClangRemoveRedarrayPass(*PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +class ClangRemoveRedarrayInfo final : public tsar::PassGroupInfo { + void addBeforePass(legacy::PassManager &Passes) const override; + void addAfterPass(legacy::PassManager &Passes) const override; +}; +} // namespace + +void ClangRemoveRedarrayInfo::addBeforePass( + legacy::PassManager &Passes) const { + addImmutableAliasAnalysis(Passes); + addInitialTransformations(Passes); + Passes.add(createAnalysisSocketImmutableStorage()); + Passes.add(createDIMemoryTraitPoolStorage()); + Passes.add(createDIMemoryEnvironmentStorage()); + Passes.add(createGlobalsAccessStorage()); + Passes.add(createGlobalsAccessCollector()); + Passes.add(createDIEstimateMemoryPass()); + Passes.add(createDIMemoryAnalysisServer()); + Passes.add(createAnalysisWaitServerPass()); + Passes.add(createMemoryMatcherPass()); + Passes.add(createAnalysisWaitServerPass()); +} + +void ClangRemoveRedarrayInfo::addAfterPass(legacy::PassManager &Passes) const { + Passes.add(createAnalysisReleaseServerPass()); + Passes.add(createAnalysisCloseConnectionPass()); +} + +void ClangRemoveRedarray::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + //AU.setPreservesAll(); +} + +char ClangRemoveRedarray::ID = 0; + +INITIALIZE_PASS_IN_GROUP_BEGIN(ClangRemoveRedarray, "clang-remove-redarray", + "Remove Redarray (Clang)", false, false, + TransformationQueryManager::getPassRegistry()) +INITIALIZE_PASS_IN_GROUP_INFO(ClangRemoveRedarrayInfo) +INITIALIZE_PASS_DEPENDENCY(CanonicalLoopPass) +INITIALIZE_PASS_DEPENDENCY(ClangPerfectLoopPass) +INITIALIZE_PASS_DEPENDENCY(ClangDIMemoryMatcherPass) +INITIALIZE_PASS_DEPENDENCY(ClangGlobalInfoPass) +INITIALIZE_PASS_DEPENDENCY(DIEstimateMemoryPass) +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) +INITIALIZE_PASS_DEPENDENCY(EstimateMemoryPass) +INITIALIZE_PASS_DEPENDENCY(GlobalOptionsImmutableWrapper) +INITIALIZE_PASS_DEPENDENCY(MemoryMatcherImmutableWrapper) +INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(TransformationEnginePass) +INITIALIZE_PASS_IN_GROUP_END(ClangRemoveRedarray, "clang-remove-redarray", + "Remove Redarray (Clang)", false, false, + TransformationQueryManager::getPassRegistry()) + +namespace { +class RedarrayClauseVisitor + : public clang::RecursiveASTVisitor { +public: + explicit RedarrayClauseVisitor( + SmallVectorImpl> &Ls, + std::vector> &decls, + std::vector> &sizes) + : mLiterals(Ls), mDecls(decls), mSizes(sizes) {} + bool VisitStringLiteral(clang::StringLiteral *SL) { + LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "visit string literal RedarrayClauseVisitor, string: " << SL->getString() << "\n"); + if (SL->getString() != getName(ClauseId::RemoveRedarray)) + mLiterals.emplace_back(SL->getString(), mClause); + return true; + } + bool VisitDeclRefExpr(clang::DeclRefExpr* DE) { + LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "visit decl ref expr RedarrayClauseVisitor, found: " << DE->getNameInfo().getAsString() << "\n"); + mLiterals.emplace_back(DE->getNameInfo().getAsString(), DE); + mDecls.emplace_back(DE->getNameInfo().getAsString(), DE); + return true; + } + bool VisitIntegerLiteral(clang::IntegerLiteral* DE) { + LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "visit IntegerLiteral RedarrayClauseVisitor\n"); + mLiterals.emplace_back("", DE); + mSizes.emplace_back("", DE); + return true; + } + + void setClause(clang::Stmt *C) noexcept { mClause = C; } + +private: + SmallVectorImpl> &mLiterals; + std::vector> &mDecls; + std::vector> &mSizes; + clang::Stmt *mClause{nullptr}; +}; + +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + +class ClangRemoveRedarrayVisitor + : public clang::RecursiveASTVisitor { + enum LoopKind : uint8_t { + Ok = 0, + NotCanonical = 1u << 0, + NotPerfect = 1u << 1, + NotAnalyzed = 1u << 2, + HasDependency = 1u << 3, + LLVM_MARK_AS_BITMASK_ENUM(HasDependency) + }; + + using VarList = SmallVector; + + using LoopNest = SmallVector< + std::tuple, + 4>; + +public: + ClangRemoveRedarrayVisitor(ClangRemoveRedarray &P, llvm::Function &F, + ClangTransformationContext *TfmCtx, + const ASTImportInfo &ImportInfo) + : mImportInfo(ImportInfo), mRewriter(TfmCtx->getRewriter()), + mSrcMgr(mRewriter.getSourceMgr()), mLangOpts(mRewriter.getLangOpts()), + mRawInfo(P.getAnalysis().getGlobalInfo(TfmCtx)->RI), + mGlobalOpts( + P.getAnalysis().getOptions()), + mMemMatcher(P.getAnalysis()->Matcher), + mDIMemMatcher(P.getAnalysis().getMatcher()), + mPerfectLoopInfo( + P.getAnalysis().getPerfectLoopInfo()), + mCanonicalLoopInfo( + P.getAnalysis().getCanonicalLoopInfo()), + mAT(P.getAnalysis().getAliasTree()), + mTLI(P.getAnalysis().getTLI(F)), + mDT(P.getAnalysis().getDomTree()), + mDIMInfo(P.getAnalysis().getAliasTree(), P, F) + { + if (mDIMInfo.isValid()) + mSTR = SpanningTreeRelation{mDIMInfo.DIAT}; + } + + + bool TraverseVarDecl(clang::VarDecl *VD) { + if (mStatus == FIND_INDEX) { + mIndex = VD; + } + return RecursiveASTVisitor::TraverseVarDecl(VD); + } + + bool TraverseDecl(clang::Decl *D) { + if (!D) + return RecursiveASTVisitor::TraverseDecl(D); + if (mStatus == TRAVERSE_STMT) { + toDiag(mSrcMgr.getDiagnostics(), D->getLocation(), + tsar::diag::warn_interchange_not_for_loop); // TODO: change this warning + resetVisitor(); + } + return RecursiveASTVisitor::TraverseDecl(D); + } + + bool TraverseBinaryOperator(clang::BinaryOperator * B) { + if (mStatus != GET_ALL_ARRAY_SUBSCRIPTS) { + return RecursiveASTVisitor::TraverseBinaryOperator(B); + } + return RecursiveASTVisitor::TraverseBinaryOperator(B); + } + + bool TraverseUnaryOperator(clang::UnaryOperator *U) { + if (mStatus != GET_ALL_ARRAY_SUBSCRIPTS) { + return RecursiveASTVisitor::TraverseUnaryOperator(U); + } + return RecursiveASTVisitor::TraverseUnaryOperator(U); + } + + std::string addSuffix(std::string prefix) { + int i = 0; + while (mRawInfo.Identifiers.count(prefix + std::to_string(i)) > 0) { i++; } + return prefix + std::to_string(i); + } + + bool TraverseStmt(clang::Stmt *S) { + if (!S) + return RecursiveASTVisitor::TraverseStmt(S); + switch (mStatus) { + case SEARCH_PRAGMA: { + Pragma P{*S}; + llvm::SmallVector Clauses; + if (!findClause(P, ClauseId::RemoveRedarray, Clauses)) + return RecursiveASTVisitor::TraverseStmt(S); + LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "found remove_redarray clause\n"); + RedarrayClauseVisitor SCV{mSwaps, mDecls, mSizes}; + for (auto *C : Clauses) { + SCV.setClause(C); + SCV.TraverseStmt(C); + } + mIsStrict = !findClause(P, ClauseId::NoStrict, Clauses); + LLVM_DEBUG(if (!mIsStrict) dbgs() + << DEBUG_PREFIX << "found 'nostrict' clause\n"); + llvm::SmallVector ToRemove; + auto IsPossible{pragmaRangeToRemove(P, Clauses, mSrcMgr, mLangOpts, + mImportInfo, ToRemove)}; + if (!IsPossible.first) + if (IsPossible.second & PragmaFlags::IsInMacro) + toDiag(mSrcMgr.getDiagnostics(), Clauses.front()->getBeginLoc(), + tsar::diag::warn_remove_directive_in_macro); + else if (IsPossible.second & PragmaFlags::IsInHeader) + toDiag(mSrcMgr.getDiagnostics(), Clauses.front()->getBeginLoc(), + tsar::diag::warn_remove_directive_in_include); + else + toDiag(mSrcMgr.getDiagnostics(), Clauses.front()->getBeginLoc(), + tsar::diag::warn_remove_directive); + clang::Rewriter::RewriteOptions RemoveEmptyLine; + /// TODO (kaniandr@gmail.com): it seems that RemoveLineIfEmpty is + /// set to true then removing (in RewriterBuffer) works incorrect. + RemoveEmptyLine.RemoveLineIfEmpty = false; + for (auto SR : ToRemove) + mRewriter.RemoveText(SR, RemoveEmptyLine); + Clauses.clear(); + // TODO: insert variable declaration here + mStatus = TRAVERSE_STMT; + return true; + } + case TRAVERSE_STMT: { + LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "enter traverse_stmt stage\n"); + if (!isa(S)) { + toDiag(mSrcMgr.getDiagnostics(), S->getBeginLoc(), + tsar::diag::warn_interchange_not_for_loop); // TODO: change this warn + resetVisitor(); + return RecursiveASTVisitor::TraverseStmt(S); + } + bool HasMacro{false}; + for_each_macro(S, mSrcMgr, mLangOpts, mRawInfo.Macros, + [&HasMacro, this](clang::SourceLocation Loc) { + if (!HasMacro) { + toDiag(mSrcMgr.getDiagnostics(), Loc, + tsar::diag::note_assert_no_macro); + HasMacro = true; + } + }); + if (HasMacro) { + resetVisitor(); + return RecursiveASTVisitor::TraverseStmt(S); + } + if (mDecls.size() != mSizes.size()) { + LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "number of arrays does not match number of their sizes\n"); + return false; + } + std::string variableDeclaration = ""; + for (int i = 0; i < mDecls.size(); i++) { + auto [ArrName, ArrayStmt] = mDecls[i]; + auto [SizeLiteral, SizeStmt] = mSizes[i]; + const clang::Type* ArrayType = cast(ArrayStmt)->getType().getTypePtr(); + if (!isa(ArrayType) && !isa(ArrayType)) { + LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "statement in the pragma is not array or pointer\n"); + return false; + } + std::string ToInsert; + if (isa(ArrayType)) { + ToInsert = cast(ArrayType)->getElementType().getAsString(); + } + else if (isa(ArrayType)) { + ToInsert = cast(ArrayType)->getPointeeType().getAsString(); + } + arrayVarNames[ArrName] = std::vector(); + for (int i = 0; i < cast(SizeStmt)->getValue().getSExtValue(); i++) { + if (i > 0) { + ToInsert += ","; + } + std::string newVarName = addSuffix(ArrName + "_subscr_" + std::to_string(i) + "_"); + arrayVarNames[ArrName].push_back(newVarName); + ToInsert += (" " + newVarName + " = " + ArrName + "[" + std::to_string(i) + "]"); + } + ToInsert += (";\n"); + variableDeclaration += ToInsert; + } + mStatus = FIND_INDEX; + auto Res = RecursiveASTVisitor::TraverseStmt(S); + mStatus = FIND_OP; + Res = RecursiveASTVisitor::TraverseStmt(S); + if (checksPassed) { + mRewriter.InsertTextBefore(S->getBeginLoc(), + variableDeclaration); // insert array variables + // definitions here + for (int i = 0; i < rangeToReplace.size(); i++) { + mRewriter.ReplaceText(rangeToReplace[i], textToReplace[i]); + } + for (int i = 0; i < mDecls.size(); i++) { + auto [ArrName, ArrayStmt] = mDecls[i]; + auto [SizeLiteral, SizeStmt] = mSizes[i]; + std::string ToInsert = ""; + for (int i = 0; i < cast(SizeStmt)->getValue().getSExtValue(); i++) { + ToInsert += ArrName + "[" + std::to_string(i) + "] = " + arrayVarNames[ArrName][i] + ";\n"; + } + mRewriter.InsertTextAfterToken(S->getEndLoc(), ToInsert); + } + } + else { + return false; + } + return true; + + } + case FIND_INDEX: { + return RecursiveASTVisitor::TraverseStmt(S); + } + case FIND_OP: { + if (!isa(S) && !isa(S)) { + return RecursiveASTVisitor::TraverseStmt(S); + } + mStatus = GET_ALL_ARRAY_SUBSCRIPTS; + if (isa(S)) { + auto Res = RecursiveASTVisitor::TraverseBinaryOperator(cast(S)); + } else if (isa(S)) { + auto Res = RecursiveASTVisitor::TraverseUnaryOperator(cast(S)); + } + else { + LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "unsupported operator\n"); + return false; + } + mStatus = FIND_OP; + if (mArraySubscriptExpr.size() == 0) { + return RecursiveASTVisitor::TraverseStmt(S); + } + int declIndex = -1; + for (int i = 0; i < mDecls.size(); i++) { + auto [SizeLiteral, SizeStmt] = mSizes[i]; + auto [ArrName, ArrayStmt] = mDecls[i]; + if (mRewriter.getRewrittenText(mArraySubscriptExpr[0]->getLHS()->getSourceRange()) == ArrName) { + declIndex = i; + } + } + if (declIndex == -1) { + return RecursiveASTVisitor::TraverseStmt(S); + } + for (int j = 1; j < mArraySubscriptExpr.size(); j++) { + if (mRewriter.getRewrittenText(mArraySubscriptExpr[j]->getLHS()->getSourceRange()) != + mRewriter.getRewrittenText(mArraySubscriptExpr[0]->getLHS()->getSourceRange())) { + bool arrayJInPragma = false; + bool array0InPragma = false; + for (int i = 0; i < mDecls.size(); i++) { + auto [ArrName, ArrayStmt] = mDecls[i]; + if (ArrName == mRewriter.getRewrittenText(mArraySubscriptExpr[0]->getLHS()->getSourceRange())) { + array0InPragma = true; + } + if (ArrName == mRewriter.getRewrittenText(mArraySubscriptExpr[j]->getLHS()->getSourceRange())) { + arrayJInPragma = true; + } + } + if (arrayJInPragma && array0InPragma) { + LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "different arrays in operator are not yet supported\n"); + checksPassed = false; + return false; + } + } + } + auto [ArrName, ArrayStmt] = mDecls[declIndex]; + auto [SizeLiteral, SizeStmt] = mSizes[declIndex]; + std::string switchText = "switch (" + mRewriter.getRewrittenText(mArraySubscriptExpr[0]->getRHS()->getSourceRange()) + ") {\n"; + for (int i = 0; i < cast(SizeStmt)->getValue().getSExtValue(); i++) { + ExternalRewriter Canvas(clang::SourceRange(S->getBeginLoc(), S->getEndLoc()), mSrcMgr, mLangOpts); + auto ArrSize = cast(SizeStmt)->getValue().getSExtValue(); + for (auto Subscr: mArraySubscriptExpr) { + Canvas.ReplaceText(clang::SourceRange(Subscr->getBeginLoc(), Subscr->getEndLoc()), arrayVarNames[ArrName][i]); + } + std::string caseBody = Canvas.getRewrittenText(clang::SourceRange(S->getBeginLoc(), S->getEndLoc())).str(); + switchText += "case " + std::to_string(i) + ":\n" + caseBody + ";\nbreak;\n"; + } + switchText += "}"; + bool sourceRangeInArray = false; + for (auto range : rangeToReplace) { + if (range.fullyContains(S->getSourceRange())) { + sourceRangeInArray = true; + } + } + if (!sourceRangeInArray) { + rangeToReplace.push_back(S->getSourceRange()); + textToReplace.push_back(switchText); + } + clearArraySubscr(); + return RecursiveASTVisitor::TraverseStmt(S); + } + case GET_ALL_ARRAY_SUBSCRIPTS: { + if (!isa(S)) { + return RecursiveASTVisitor::TraverseStmt(S); + } + mIsSubscriptUseful = false; + mStatus = CHECK_SUBSCRIPT; + auto Res = RecursiveASTVisitor::TraverseStmt(S); + mStatus = GET_ALL_ARRAY_SUBSCRIPTS; + if (mIsSubscriptUseful) { + mArraySubscriptExpr.push_back(cast(S)); + } + return RecursiveASTVisitor::TraverseStmt(S); + } + case CHECK_SUBSCRIPT: { + if (!isa(S)) { + return RecursiveASTVisitor::TraverseStmt(S); + } + auto Arr = cast(S); + for (int i = 0; i < mDecls.size(); i++) { + auto [ArrName, ArrayStmt] = mDecls[i]; + if (ArrName == Arr->getNameInfo().getName().getAsString()) { + mIsSubscriptUseful = true; + return true; + } + } + return RecursiveASTVisitor::TraverseStmt(S); + } + } + return RecursiveASTVisitor::TraverseStmt(S); + } + + +private: + void resetVisitor() { + mStatus = SEARCH_PRAGMA; + mSwaps.clear(); + mDecls.clear(); + mSizes.clear(); + mInductions.clear(); + arrayVarNames.clear(); + rangeToReplace.clear(); + textToReplace.clear(); + checksPassed = true; + } + + void clearArraySubscr() { + mArraySubscriptExpr.clear(); + } + + + + const ASTImportInfo mImportInfo; + clang::Rewriter &mRewriter; + clang::SourceManager &mSrcMgr; + const clang::LangOptions &mLangOpts; + ClangGlobalInfo::RawInfo &mRawInfo; + const GlobalOptions &mGlobalOpts; + MemoryMatchInfo::MemoryMatcher &mMemMatcher; + const ClangDIMemoryMatcherPass::DIMemoryMatcher &mDIMemMatcher; + const CanonicalLoopSet &mCanonicalLoopInfo; + PerfectLoopInfo &mPerfectLoopInfo; + AliasTree &mAT; + TargetLibraryInfo &mTLI; + DominatorTree &mDT; + DIMemoryClientServerInfo mDIMInfo; + std::optional> mSTR; + bool mIsStrict{true}; + enum Status { + SEARCH_PRAGMA, + TRAVERSE_STMT, + FIND_INDEX, + FIND_OP, + GET_ALL_ARRAY_SUBSCRIPTS, + CHECK_SUBSCRIPT, + } mStatus{SEARCH_PRAGMA}; + SmallVector, 4> mSwaps; + std::vector> mDecls; + std::vector> mSizes; + std::map > arrayVarNames; + std::vector mArraySubscriptExpr; + std::vector rangeToReplace; + std::vector textToReplace; + bool mIsSubscriptUseful; + bool checksPassed = true; + clang::VarDecl* mIndex; + + LoopNest mInductions; +}; +} // namespace + +bool ClangRemoveRedarray::runOnFunction(Function &F) { + + auto *DISub{findMetadata(&F)}; + if (!DISub) + return false; + auto *CU{DISub->getUnit()}; + if (!isC(CU->getSourceLanguage()) && !isCXX(CU->getSourceLanguage())) + return false; + auto &TfmInfo{getAnalysis()}; + auto *TfmCtx{TfmInfo ? dyn_cast_or_null( + TfmInfo->getContext(*CU)) + : nullptr}; + if (!TfmCtx || !TfmCtx->hasInstance()) { + F.getContext().emitError("can not transform sources" + ": transformation context is not available"); + return false; + } + auto *FD{TfmCtx->getDeclForMangledName(F.getName())}; + if (!FD) + return false; + ASTImportInfo ImportStub; + const auto *ImportInfo{&ImportStub}; + if (auto *ImportPass = getAnalysisIfAvailable()) + ImportInfo = &ImportPass->getImportInfo(); + ClangRemoveRedarrayVisitor(*this, F, TfmCtx, *ImportInfo).TraverseDecl(FD); + return false; +}