From 1b0bf7d003aae85d7ce23f1247f1b75d07ed4836 Mon Sep 17 00:00:00 2001 From: yukatan1701 Date: Thu, 5 Dec 2019 15:03:57 +0300 Subject: [PATCH 01/10] [TSAR, Transform] Create loop swapping tranformation. --- include/tsar/Support/Directives.td | 2 + include/tsar/Transform/Clang/LoopSwapping.h | 88 +++ include/tsar/Transform/Clang/Passes.h | 8 + lib/Transform/Clang/CMakeLists.txt | 3 +- lib/Transform/Clang/LoopSwapping.cpp | 581 ++++++++++++++++++++ lib/Transform/Clang/Passes.cpp | 1 + 6 files changed, 682 insertions(+), 1 deletion(-) create mode 100644 include/tsar/Transform/Clang/LoopSwapping.h create mode 100644 lib/Transform/Clang/LoopSwapping.cpp diff --git a/include/tsar/Support/Directives.td b/include/tsar/Support/Directives.td index 76468bea..6d1e4ff7 100644 --- a/include/tsar/Support/Directives.td +++ b/include/tsar/Support/Directives.td @@ -130,6 +130,8 @@ def Replace : Clause<"replace", Transform, def With : Clause<"with", Transform, [LParen, Identifier, RParen]>; +def SwapLoops: Clause<"swaploops", Transform>; + def Private : Clause<"private", Analysis, [LParen, Identifier, ZeroOrMore<[Comma, Identifier]>, RParen]>; diff --git a/include/tsar/Transform/Clang/LoopSwapping.h b/include/tsar/Transform/Clang/LoopSwapping.h new file mode 100644 index 00000000..73a01820 --- /dev/null +++ b/include/tsar/Transform/Clang/LoopSwapping.h @@ -0,0 +1,88 @@ +//=== LoopSwapping.h - Loop Swapping (Clang) ----*- C++ -*===// +// +// Traits Static Analyzer (SAPFOR) +// +// Copyright 2018 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. +// +//===---------------------------------------------------------------------===// +// +// The file declares a pass to perform swapping of specific loops. +// +//===---------------------------------------------------------------------===// + +#ifndef TSAR_CLANG_LOOP_SWAPPING_H +#define TSAR_CLANG_LOOP_SWAPPING_H + +#include "tsar/Support/Tags.h" +#include "tsar/Transform/Clang/Passes.h" +#include "tsar/Analysis/AnalysisServer.h" +#include "tsar/Analysis/Memory/DIDependencyAnalysis.h" +#include "tsar/Support/GlobalOptions.h" +#include +#include + +namespace tsar { + class TransformationContext; + class DIAliasNode; + class DIAliasTree; + class MemoryMatchInfo; +} + +namespace clang { + class SourceRange; + class Rewriter; +} + +namespace llvm { + +class Loop; +class MDNode; +class GlobalsAAResult; + +class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { +public: + static char ID; + + ClangLoopSwapping() : FunctionPass(ID) { + initializeClangLoopSwappingPass(*PassRegistry::getPassRegistry()); + } + bool runOnFunction(Function &F) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; + void releaseMemory() override; + +private: + void initializeProviderOnClient(llvm::Module &M); + void initializeProviderOnServer(); + + bool LoadDependenceAnalysisInfo(Function &F); + void SwapLoops(const std::vector> &mRangePairs, + const std::vector> &mLoopPairs); + bool IsNoLoopID(llvm::MDNode *LoopID); + std::vector GetLoopNodes(llvm::MDNode *LoopID); + bool IsSwappingAvailable(std::vector loops); + + tsar::TransformationContext *mTfmCtx = nullptr; + tsar::DIDependencInfo *DIDepInfo = nullptr; + tsar::DIAliasTree *DIAT = nullptr; + const tsar::GlobalOptions *mGlobalOpts = nullptr; + GlobalsAAResult * mGlobalsAA = nullptr; + tsar::AnalysisSocket *mSocket = nullptr; + tsar::MemoryMatchInfo *mMemoryMatcher = nullptr; + std::function getLoopID; +}; + +} + +#endif//TSAR_CLANG_LOOP_SWAPPING_H diff --git a/include/tsar/Transform/Clang/Passes.h b/include/tsar/Transform/Clang/Passes.h index 250f08da..ba106472 100644 --- a/include/tsar/Transform/Clang/Passes.h +++ b/include/tsar/Transform/Clang/Passes.h @@ -93,4 +93,12 @@ ModulePass * createClangStructureReplacementPass(); /// with separate variables. void initializeClangStructureReplacementPassPass(PassRegistry &Registry); } +/// Creates a pass to perform swapping of loops. +FunctionPass * createClangLoopSwapping(); + +/// Initializes a pass to perform swapping of loops. +void initializeClangLoopSwappingPass(PassRegistry &Registry); + +} + #endif//TSAR_CLANG_TRANSFORM_PASSES_H diff --git a/lib/Transform/Clang/CMakeLists.txt b/lib/Transform/Clang/CMakeLists.txt index 777fd1b3..36690848 100644 --- a/lib/Transform/Clang/CMakeLists.txt +++ b/lib/Transform/Clang/CMakeLists.txt @@ -1,6 +1,7 @@ set(TRANSFORM_SOURCES Passes.cpp ExprPropagation.cpp Inline.cpp RenameLocal.cpp DeadDeclsElimination.cpp FormatPass.cpp OpenMPAutoPar.cpp - SharedMemoryAutoPar.cpp DVMHSMAutoPar.cpp StructureReplacement.cpp) + SharedMemoryAutoPar.cpp DVMHSMAutoPar.cpp StructureReplacement.cpp + LoopSwapping.cpp) if(MSVC_IDE) file(GLOB_RECURSE TRANSFORM_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/lib/Transform/Clang/LoopSwapping.cpp b/lib/Transform/Clang/LoopSwapping.cpp new file mode 100644 index 00000000..b0d514f2 --- /dev/null +++ b/lib/Transform/Clang/LoopSwapping.cpp @@ -0,0 +1,581 @@ +//===- LoopSwapping.cpp - Source-level Renaming of Local Objects - *- C++ -*===// +// +// Traits Static Analyzer (SAPFOR) +// +// Copyright 2018 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. +// +//===----------------------------------------------------------------------===// +// +// The file declares a pass to perform swapping of specific loops. +// +//===----------------------------------------------------------------------===// + +#include "tsar/ADT/SpanningTreeRelation.h" +#include "tsar/Analysis/AnalysisServer.h" +#include "tsar/Transform/Clang/LoopSwapping.h" +#include "tsar/Analysis/Clang/GlobalInfoExtractor.h" +#include "tsar/Analysis/Clang/LoopMatcher.h" +#include "tsar/Analysis/Clang/MemoryMatcher.h" +#include "tsar/Analysis/Clang/NoMacroAssert.h" +#include "tsar/Analysis/Clang/SourceLocationTraverse.h" +#include "tsar/Analysis/Memory/DIDependencyAnalysis.h" +#include "tsar/Analysis/Memory/DIEstimateMemory.h" +#include "tsar/Analysis/Memory/MemoryTraitUtils.h" +#include "tsar/Analysis/Memory/ServerUtils.h" +#include "tsar/Core/Query.h" +#include "tsar/Core/TransformationContext.h" +#include "tsar/Support/Clang/Diagnostic.h" +#include "tsar/Support/Clang/Pragma.h" +#include "tsar/Support/GlobalOptions.h" +#include "tsar/Support/PassAAProvider.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace clang; +using namespace tsar; + +#undef DEBUG_TYPE +#define DEBUG_TYPE "clang-l-swap" + +char ClangLoopSwapping::ID = 0; + +namespace llvm { + +static void initializeClangLoopSwappingServerPass(PassRegistry &); +static void initializeClangLoopSwappingServerResponsePass(PassRegistry &); + +} + +namespace { + +/// This provides access to function-level analysis results on server. +using ClangLoopSwappingServerProvider = + FunctionPassAAProvider; + +/// List of responses available from server (client may request corresponding +/// analysis, in case of provider all analysis related to a provider may +/// be requested separately). +using ClangLoopSwappingServerResponse = AnalysisResponsePass< + GlobalsAAWrapperPass, DIMemoryTraitPoolWrapper, DIMemoryEnvironmentWrapper, + ClangLoopSwappingServerProvider>; + + +/// This provider access to function-level analysis results on client. +using ClangLoopSwappingProvider = + FunctionPassAAProvider; + +/// This analysis server performs transformation-based analysis. +class ClangLoopSwappingServer final : public AnalysisServer { +public: + static char ID; + ClangLoopSwappingServer() : AnalysisServer(ID) { + initializeClangLoopSwappingServerPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AnalysisServer::getAnalysisUsage(AU); + ClientToServerMemory::getAnalysisUsage(AU); + AU.addRequired(); + } + + void prepareToClone(llvm::Module &ClientM, + ValueToValueMapTy &ClientToServer) override { + ClientToServerMemory::prepareToClone(ClientM, ClientToServer); + } + + void initializeServer(llvm::Module &CM, llvm::Module &SM, ValueToValueMapTy &CToS, + legacy::PassManager &PM) override { + auto &GO = getAnalysis(); + PM.add(createGlobalOptionsImmutableWrapper(&GO.getOptions())); + PM.add(createDIMemoryTraitPoolStorage()); + ClientToServerMemory::initializeServer(*this, CM, SM, CToS, PM); + } + + void addServerPasses(llvm::Module &M, legacy::PassManager &PM) override { + auto &GO = getAnalysis().getOptions(); + addImmutableAliasAnalysis(PM); + addBeforeTfmAnalysis(PM); + addAfterSROAAnalysis(GO, M.getDataLayout(), PM); + addAfterLoopRotateAnalysis(PM); + PM.add(createVerifierPass()); + PM.add(new ClangLoopSwappingServerResponse); + } + + void prepareToClose(legacy::PassManager &PM) override { + ClientToServerMemory::prepareToClose(PM); + } +}; + +class LoopVisitor : public RecursiveASTVisitor { +public: + LoopVisitor(Rewriter &Rewr, const LoopMatcherPass::LoopMatcher &LM) : + mRewriter(Rewr), + mLoopInfo(LM), + mSrcMgr(Rewr.getSourceMgr()), + mLangOpts(Rewr.getLangOpts()), + mIsInScope(false), mForStack(nullptr) + {} + + void EnterInScope() { + mForLocations.clear(); + mForIRs.clear(); + mIsInScope = true; + } + + void ExitFromScope() { + mForLocations.clear(); + mForIRs.clear(); + mIsInScope = false; + } + + bool IsInScope() { + return mIsInScope; + } + + bool TraverseStmt(Stmt *S) { + if (!S) + return true; + Pragma P(*S); + if (P) { + // Search for loop swapping clause and disable renaming in other pragmas. + if (findClause(P, ClauseId::SwapLoops, mClauses)) { + llvm::SmallVector ToRemove; + auto IsPossible = + pragmaRangeToRemove(P, mClauses, mSrcMgr, mLangOpts, ToRemove); + if (!IsPossible.first) + if (IsPossible.second & PragmaFlags::IsInMacro) + toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getLocStart(), + diag::warn_remove_directive_in_macro); + else if (IsPossible.second & PragmaFlags::IsInHeader) + toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getLocStart(), + diag::warn_remove_directive_in_include); + else + toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getLocStart(), + diag::warn_remove_directive); + 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); + EnterInScope(); + } + return true; + } + auto Res = RecursiveASTVisitor::TraverseStmt(S); + return Res; + } + + bool TraverseCompoundStmt(CompoundStmt *S) { + if (IsInScope() && mForStack == nullptr) { + mForStack = new std::stack; + mForLocations.clear(); + mForIRs.clear(); + auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S); + while (!mForStack->empty()) + mForStack->pop(); + delete mForStack; + mForStack = nullptr; + + mRangePairs.push_back(mForLocations); + mLoopPairs.push_back(mForIRs); + + ExitFromScope(); + return Res; + } + return RecursiveASTVisitor::TraverseCompoundStmt(S); + } + + bool TraverseForStmt(ForStmt *S) { + if (IsInScope() && mForStack != nullptr) { + if (mForStack->empty()) { + auto Match = mLoopInfo.find(S); + if (Match != mLoopInfo.end()) { + Loop *loop = Match->get(); + mForIRs.push_back(loop); + SourceRange range(S->getBeginLoc(), S->getEndLoc()); + mForLocations.push_back(range); + } + mForStack->push(S); + auto Res = RecursiveASTVisitor::TraverseForStmt(S); + mForStack->pop(); + return Res; + } + } + return RecursiveASTVisitor::TraverseForStmt(S); + } + + std::vector> getRangePairs() { + return mRangePairs; + } + + std::vector> getLoopPairs() { + return mLoopPairs; + } + + void PrintLocations() { + LLVM_DEBUG(dbgs() << "'for' loop locations:\n"); + for (auto locs: mRangePairs) { + for (auto location : locs) { + SourceLocation begin = location.getBegin(); + SourceLocation end = location.getEnd(); + LLVM_DEBUG(dbgs() << "Begin: "); + begin.print(dbgs(), mSrcMgr); + LLVM_DEBUG(dbgs() << "; End: "); + end.print(dbgs(), mSrcMgr); + LLVM_DEBUG(dbgs() << '\n'); + } + } + } + +private: + Rewriter &mRewriter; + SourceManager &mSrcMgr; + const LangOptions &mLangOpts; + bool mIsInScope; + const LoopMatcherPass::LoopMatcher &mLoopInfo; + + SmallVector mClauses; + std::vector mForLocations; + std::vector mForIRs; + std::vector> mRangePairs; + std::vector> mLoopPairs; + std::stack *mForStack; +}; + +class ClangLoopSwappingInfo final : public PassGroupInfo { + void addBeforePass(legacy::PassManager &Passes) const override { + addImmutableAliasAnalysis(Passes); + addInitialTransformations(Passes); + Passes.add(createAnalysisSocketImmutableStorage()); + Passes.add(createDIMemoryTraitPoolStorage()); + Passes.add(createDIMemoryEnvironmentStorage()); + Passes.add(createDIEstimateMemoryPass()); + Passes.add(new ClangLoopSwappingServer); + Passes.add(createAnalysisWaitServerPass()); + Passes.add(createMemoryMatcherPass()); + } + + void addAfterPass(legacy::PassManager &Passes) const override { + Passes.add(createAnalysisReleaseServerPass()); + Passes.add(createAnalysisCloseConnectionPass()); + } +}; + +} + +void ClangLoopSwapping::initializeProviderOnClient(llvm::Module &M) { + ClangLoopSwappingProvider::initialize( + [this](GlobalOptionsImmutableWrapper &Wrapper) { + Wrapper.setOptions(mGlobalOpts); + }); + ClangLoopSwappingProvider::initialize( + [this](AnalysisSocketImmutableWrapper &Wrapper) { + Wrapper.set(*mSocket); + }); + ClangLoopSwappingProvider::initialize( + [this, &M](TransformationEnginePass &Wrapper) { + Wrapper.setContext(M, mTfmCtx); + }); + ClangLoopSwappingProvider::initialize( + [this](MemoryMatcherImmutableWrapper &Wrapper) { + Wrapper.set(*mMemoryMatcher); + }); + ClangLoopSwappingProvider::initialize< + GlobalsAAResultImmutableWrapper>( + [this](GlobalsAAResultImmutableWrapper &Wrapper) { + Wrapper.set(*mGlobalsAA); + }); +} + +void ClangLoopSwapping::initializeProviderOnServer() { + ClangLoopSwappingServerProvider::initialize( + [this](GlobalOptionsImmutableWrapper &Wrapper) { + Wrapper.setOptions(mGlobalOpts); + }); + auto R = mSocket->getAnalysis(); + assert(R && "Immutable passes must be available on server!"); + auto *DIMEnvServer = R->value(); + ClangLoopSwappingServerProvider::initialize( + [DIMEnvServer](DIMemoryEnvironmentWrapper &Wrapper) { + Wrapper.set(**DIMEnvServer); + }); + auto *DIMTraitPoolServer = R->value(); + ClangLoopSwappingServerProvider::initialize( + [DIMTraitPoolServer](DIMemoryTraitPoolWrapper &Wrapper) { + Wrapper.set(**DIMTraitPoolServer); + }); + auto &GlobalsAAServer = R->value()->getResult(); + ClangLoopSwappingServerProvider::initialize( + [&GlobalsAAServer](GlobalsAAResultImmutableWrapper &Wrapper) { + Wrapper.set(GlobalsAAServer); + }); + +} + +void ClangLoopSwapping::releaseMemory() { + mTfmCtx = nullptr; + DIDepInfo = nullptr; + DIAT = nullptr; + mGlobalOpts = nullptr; + mGlobalsAA = nullptr; + mSocket = nullptr; + mMemoryMatcher = nullptr; +} + +bool ClangLoopSwapping::IsNoLoopID(MDNode *LoopID) { + if (!LoopID || !(LoopID = getLoopID(LoopID))) { + dbgs() << "[LOOP SWAPPING]: ignore loop without ID."; + return true; + } + return false; +} + +std::vector ClangLoopSwapping::GetLoopNodes(MDNode *LoopID) { + auto DepItr = DIDepInfo->find(LoopID); + assert(DepItr != DIDepInfo->end() && "Loop must be analyzed!"); + auto &DIDepSet = DepItr->get(); + DenseSet Coverage; + auto tmp = mGlobalOpts->IgnoreRedundantMemory; + auto &tmp2 = *DIAT; + dbgs() << "Here1\n"; + accessCoverage(DIDepSet, tmp2, Coverage, + tmp); + dbgs() << "Here2\n"; + std::vector nodes; + for (auto &TS : DIDepSet) { + auto node = TS.getNode(); + //TS.print(dbgs() << "[LOOP SWAPPING]: current node is: "); + if (!Coverage.count(node)) + continue; + MemoryDescriptor Dptr = TS; + if (Dptr.is()) { + dbgs() << "[LOOP SWAPPING]: readonly node found (" << TS.getNode() << ")\n"; + continue; + } + if (Dptr.is()) { + dbgs() << "[LOOP SWAPPING]: reduction node found (" << TS.getNode() << "); type: "; + auto I = TS.begin(), EI = TS.end(); + auto *Red = (**I).get(); + auto Kind = Red->getKind(); + if (!Red || Kind == trait::DIReduction::RK_NoReduction) { + dbgs() << "No Reduction\n"; + } else if (Kind == trait::DIReduction::RK_Add) { + dbgs() << "Add\n"; + } else if (Kind == trait::DIReduction::RK_Mult) { + dbgs() << "Mult\n"; + } + continue; + } + if (Dptr.is()) { + dbgs() << "[LOOP SWAPPING]: shared node found (" << TS.getNode() << ")\n"; + continue; + } + if (TS.is()) { + dbgs() << "[LOOP SWAPPING]: induction node found (" << TS.getNode() << ")\n"; + continue; + } + nodes.push_back(const_cast(node)); + } + return nodes; +} + +bool ClangLoopSwapping::IsSwappingAvailable(std::vector loops) { + Loop *loop0 = loops[0]; + Loop *loop1 = loops[1]; + + auto *Loop0_ID = loop0->getLoopID(); + auto *Loop1_ID = loop1->getLoopID(); + + + if (IsNoLoopID(Loop0_ID) || IsNoLoopID(Loop1_ID)) { + dbgs() << "[LOOP SWAPPING]: No loop ID.\n"; + return false; + } + std::vector nodes0 = GetLoopNodes(Loop0_ID); + std::vector nodes1 = GetLoopNodes(Loop1_ID); + SpanningTreeRelation STR(DIAT); + for (auto *node0: nodes0) { + for (auto *node1: nodes1) { + if (!STR.isUnreachable(node0, node1)) + return false; + } + } + + return true; +} + +void ClangLoopSwapping::SwapLoops(const std::vector> &mRangePairs, + const std::vector> &mLoopPairs) { + Rewriter &mRewriter = mTfmCtx->getRewriter(); + for (int i = 0; i < mRangePairs.size(); i++) { + std::vector ranges = mRangePairs[i]; + std::vector loops = mLoopPairs[i]; + + if (ranges.size() < 2) { + dbgs() << "[LOOP SWAPPING]: Too few loops for swap. Ignore.\n"; + continue; + } + if (ranges.size() > 2) { + dbgs() << "[LOOP SWAPPING]: Too many loops for swap. Ignore additional loops.\n"; + } + if (IsSwappingAvailable(loops)) { + SourceRange first = ranges[0]; + SourceRange second = ranges[1]; + std::string first_loop = mRewriter.getRewrittenText(first); + std::string second_loop = mRewriter.getRewrittenText(second); + mRewriter.ReplaceText(first, second_loop); + mRewriter.ReplaceText(second, first_loop); + } else { + dbgs() << "[LOOP SWAPPING]: Failed to swap loops: shared memory\n"; + } + } +} + +bool ClangLoopSwapping::LoadDependenceAnalysisInfo(Function &F) { + getLoopID = [](ObjectID ID) { return ID; }; + if (auto *Socket = getAnalysisIfAvailable()) { + if (auto R = (*Socket)->getAnalysis()) { + auto *Matcher = R->value(); + getLoopID = [Matcher](ObjectID ID) { + auto ServerID = (*Matcher)->getMappedMD(ID); + return ServerID ? cast(*ServerID) : nullptr; + }; + if (auto R =(*Socket)->getAnalysis< + DIEstimateMemoryPass, DIDependencyAnalysisPass>(F)) { + DIAT = &R->value()->getAliasTree(); + DIDepInfo = &R->value()->getDependencies(); + } + } + } + if (!DIAT || !DIDepInfo) { + dbgs() << "[LOOP SWAPPING]: analysis server is not available\n"; + if (auto *P = getAnalysisIfAvailable()) + DIAT = &P->getAliasTree(); + else + return false; + if (auto *P = getAnalysisIfAvailable()) + DIDepInfo = &P->getDependencies(); + else + return false; + dbgs() << "[LOOP SWAPPING]: use dependence analysis from client\n"; + } + return true; +} + +bool ClangLoopSwapping::runOnFunction(Function &F) { + dbgs() << "test\n"; + auto *M = F.getParent(); + mTfmCtx = getAnalysis().getContext(*M); + if (!mTfmCtx || !mTfmCtx->hasInstance()) { + M->getContext().emitError("can not transform sources" + ": transformation context is not available"); + return false; + } + auto FuncDecl = mTfmCtx->getDeclForMangledName(F.getName()); + if (!FuncDecl) + return false; + + mSocket = &getAnalysis().get(); + mMemoryMatcher = &getAnalysis().get(); + mGlobalOpts = &getAnalysis().getOptions(); + mGlobalsAA = &getAnalysis().getResult(); + initializeProviderOnClient(*M); + initializeProviderOnServer(); + if (!LoadDependenceAnalysisInfo(F)) + return false; + + auto &mLoopInfo = getAnalysis().getMatcher(); + LoopVisitor lv(mTfmCtx->getRewriter(), mLoopInfo); + lv.TraverseDecl(FuncDecl); + lv.PrintLocations(); + std::vector> mRangePairs = lv.getRangePairs(); + std::vector> mLoopPairs = lv.getLoopPairs(); + + //auto &Provider = getAnalysis(F); + SwapLoops(mRangePairs, mLoopPairs); + return false; +} + +void ClangLoopSwapping::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.addRequired(); + AU.setPreservesAll(); +} + +FunctionPass * llvm::createClangLoopSwapping() { + return new ClangLoopSwapping(); +} + +INITIALIZE_PROVIDER(ClangLoopSwappingServerProvider, "clang-loop-swapping-server-provider", + "Loop Swapping (Clang, Server, Provider)") + +template <> char ClangLoopSwappingServerResponse::ID = 0; +INITIALIZE_PASS(ClangLoopSwappingServerResponse, "clang-loop-swapping-response", + "Loop Swapping (Clang, Server, Response)", true, + false) + +char ClangLoopSwappingServer::ID = 0; +INITIALIZE_PASS(ClangLoopSwappingServer, "clang-loop-swapping-server", + "Loop Swapping (Clang, Server)", false, false) + + +INITIALIZE_PROVIDER(ClangLoopSwappingProvider, + "clang-loop-swapping-provider", + "Loop Swapping (Clang, Provider)") + +INITIALIZE_PASS_IN_GROUP_BEGIN(ClangLoopSwapping,"clang-l-swap", + "'for' Loops Swapping (Clang)", false, false, + tsar::TransformationQueryManager::getPassRegistry()); +INITIALIZE_PASS_IN_GROUP_INFO(ClangLoopSwappingInfo); +INITIALIZE_PASS_DEPENDENCY(TransformationEnginePass); +INITIALIZE_PASS_DEPENDENCY(LoopMatcherPass); +INITIALIZE_PASS_DEPENDENCY(ClangGlobalInfoPass); +INITIALIZE_PASS_DEPENDENCY(DIDependencyAnalysisPass); +INITIALIZE_PASS_DEPENDENCY(DIEstimateMemoryPass); +INITIALIZE_PASS_DEPENDENCY(GlobalOptionsImmutableWrapper); +INITIALIZE_PASS_DEPENDENCY(DIMemoryEnvironmentWrapper); +INITIALIZE_PASS_DEPENDENCY(DIMemoryTraitPoolWrapper); +INITIALIZE_PASS_DEPENDENCY(MemoryMatcherImmutableWrapper) +INITIALIZE_PASS_DEPENDENCY(ClangLoopSwappingProvider); +INITIALIZE_PASS_DEPENDENCY(AnalysisSocketImmutableWrapper); +INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass); +INITIALIZE_PASS_DEPENDENCY(GlobalsAAResultImmutableWrapper); +INITIALIZE_PASS_DEPENDENCY(ClangLoopSwappingServerProvider); +INITIALIZE_PASS_DEPENDENCY(ClangLoopSwappingServerResponse); +INITIALIZE_PASS_IN_GROUP_END(ClangLoopSwapping,"clang-l-swap", + "'for' Loops Swapping (Clang)", false, false, + tsar::TransformationQueryManager::getPassRegistry()); \ No newline at end of file diff --git a/lib/Transform/Clang/Passes.cpp b/lib/Transform/Clang/Passes.cpp index f00b3a4f..b7fed410 100644 --- a/lib/Transform/Clang/Passes.cpp +++ b/lib/Transform/Clang/Passes.cpp @@ -36,4 +36,5 @@ void llvm::initializeClangTransform(PassRegistry &Registry) { initializeClangDeadDeclsEliminationPass(Registry); initializeClangOpenMPParallelizationPass(Registry); initializeClangDVMHSMParallelizationPass(Registry); + initializeClangLoopSwappingPass(Registry); } From 88eeb16118049fca65e31ff11efbdddecde9cebe Mon Sep 17 00:00:00 2001 From: Julia Lapenko Date: Thu, 23 Apr 2020 10:44:40 +0300 Subject: [PATCH 02/10] [TSAR, Transform] Add checks of loop for the possibility of swapping. --- include/tsar/Transform/Clang/LoopSwapping.h | 17 +- lib/Transform/Clang/LoopSwapping.cpp | 223 +++++++++----------- 2 files changed, 104 insertions(+), 136 deletions(-) diff --git a/include/tsar/Transform/Clang/LoopSwapping.h b/include/tsar/Transform/Clang/LoopSwapping.h index 73a01820..397916e2 100644 --- a/include/tsar/Transform/Clang/LoopSwapping.h +++ b/include/tsar/Transform/Clang/LoopSwapping.h @@ -37,7 +37,6 @@ namespace tsar { class TransformationContext; class DIAliasNode; class DIAliasTree; - class MemoryMatchInfo; } namespace clang { @@ -49,7 +48,6 @@ namespace llvm { class Loop; class MDNode; -class GlobalsAAResult; class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { public: @@ -63,23 +61,28 @@ class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { void releaseMemory() override; private: - void initializeProviderOnClient(llvm::Module &M); void initializeProviderOnServer(); bool LoadDependenceAnalysisInfo(Function &F); void SwapLoops(const std::vector> &mRangePairs, const std::vector> &mLoopPairs); - bool IsNoLoopID(llvm::MDNode *LoopID); - std::vector GetLoopNodes(llvm::MDNode *LoopID); + std::vector GetLoopTraits(llvm::MDNode *LoopID); + tsar::DIDependenceSet &GetLoopDepSet(MDNode *LoopID); bool IsSwappingAvailable(std::vector loops); + bool HasSameReductionKind(std::vector &traits0, + std::vector &traits1, + tsar::SpanningTreeRelation &STR); + bool HasTrueOrAntiDependence(std::vector &traits0, + std::vector &traits1, + tsar::SpanningTreeRelation &STR); + + llvm::Function *mFunction = nullptr; tsar::TransformationContext *mTfmCtx = nullptr; tsar::DIDependencInfo *DIDepInfo = nullptr; tsar::DIAliasTree *DIAT = nullptr; const tsar::GlobalOptions *mGlobalOpts = nullptr; - GlobalsAAResult * mGlobalsAA = nullptr; tsar::AnalysisSocket *mSocket = nullptr; - tsar::MemoryMatchInfo *mMemoryMatcher = nullptr; std::function getLoopID; }; diff --git a/lib/Transform/Clang/LoopSwapping.cpp b/lib/Transform/Clang/LoopSwapping.cpp index b0d514f2..5e5bfd3b 100644 --- a/lib/Transform/Clang/LoopSwapping.cpp +++ b/lib/Transform/Clang/LoopSwapping.cpp @@ -27,7 +27,6 @@ #include "tsar/Transform/Clang/LoopSwapping.h" #include "tsar/Analysis/Clang/GlobalInfoExtractor.h" #include "tsar/Analysis/Clang/LoopMatcher.h" -#include "tsar/Analysis/Clang/MemoryMatcher.h" #include "tsar/Analysis/Clang/NoMacroAssert.h" #include "tsar/Analysis/Clang/SourceLocationTraverse.h" #include "tsar/Analysis/Memory/DIDependencyAnalysis.h" @@ -52,6 +51,7 @@ #include #include + using namespace llvm; using namespace clang; using namespace tsar; @@ -78,14 +78,9 @@ using ClangLoopSwappingServerProvider = /// analysis, in case of provider all analysis related to a provider may /// be requested separately). using ClangLoopSwappingServerResponse = AnalysisResponsePass< - GlobalsAAWrapperPass, DIMemoryTraitPoolWrapper, DIMemoryEnvironmentWrapper, + DIMemoryTraitPoolWrapper, DIMemoryEnvironmentWrapper, ClangLoopSwappingServerProvider>; - -/// This provider access to function-level analysis results on client. -using ClangLoopSwappingProvider = - FunctionPassAAProvider; - /// This analysis server performs transformation-based analysis. class ClangLoopSwappingServer final : public AnalysisServer { public: @@ -198,10 +193,8 @@ class LoopVisitor : public RecursiveASTVisitor { mForStack->pop(); delete mForStack; mForStack = nullptr; - mRangePairs.push_back(mForLocations); mLoopPairs.push_back(mForIRs); - ExitFromScope(); return Res; } @@ -234,18 +227,25 @@ class LoopVisitor : public RecursiveASTVisitor { std::vector> getLoopPairs() { return mLoopPairs; } + + size_t getLoopsCount() { + return mRangePairs.size(); + } void PrintLocations() { - LLVM_DEBUG(dbgs() << "'for' loop locations:\n"); + dbgs() << "[LOOP SWAPPING]: 'for' loop locations:\n"; + unsigned int loopNumber = 0; for (auto locs: mRangePairs) { for (auto location : locs) { + dbgs() << "Loop #" << loopNumber << ":\n"; SourceLocation begin = location.getBegin(); SourceLocation end = location.getEnd(); - LLVM_DEBUG(dbgs() << "Begin: "); + dbgs() << "\tBegin: "; begin.print(dbgs(), mSrcMgr); - LLVM_DEBUG(dbgs() << "; End: "); + dbgs() << "\n\tEnd: "; end.print(dbgs(), mSrcMgr); - LLVM_DEBUG(dbgs() << '\n'); + dbgs() << '\n'; + loopNumber++; } } } @@ -275,7 +275,6 @@ class ClangLoopSwappingInfo final : public PassGroupInfo { Passes.add(createDIEstimateMemoryPass()); Passes.add(new ClangLoopSwappingServer); Passes.add(createAnalysisWaitServerPass()); - Passes.add(createMemoryMatcherPass()); } void addAfterPass(legacy::PassManager &Passes) const override { @@ -286,36 +285,12 @@ class ClangLoopSwappingInfo final : public PassGroupInfo { } -void ClangLoopSwapping::initializeProviderOnClient(llvm::Module &M) { - ClangLoopSwappingProvider::initialize( - [this](GlobalOptionsImmutableWrapper &Wrapper) { - Wrapper.setOptions(mGlobalOpts); - }); - ClangLoopSwappingProvider::initialize( - [this](AnalysisSocketImmutableWrapper &Wrapper) { - Wrapper.set(*mSocket); - }); - ClangLoopSwappingProvider::initialize( - [this, &M](TransformationEnginePass &Wrapper) { - Wrapper.setContext(M, mTfmCtx); - }); - ClangLoopSwappingProvider::initialize( - [this](MemoryMatcherImmutableWrapper &Wrapper) { - Wrapper.set(*mMemoryMatcher); - }); - ClangLoopSwappingProvider::initialize< - GlobalsAAResultImmutableWrapper>( - [this](GlobalsAAResultImmutableWrapper &Wrapper) { - Wrapper.set(*mGlobalsAA); - }); -} - void ClangLoopSwapping::initializeProviderOnServer() { ClangLoopSwappingServerProvider::initialize( [this](GlobalOptionsImmutableWrapper &Wrapper) { Wrapper.setOptions(mGlobalOpts); }); - auto R = mSocket->getAnalysisgetAnalysis< DIMemoryEnvironmentWrapper, DIMemoryTraitPoolWrapper>(); assert(R && "Immutable passes must be available on server!"); auto *DIMEnvServer = R->value(); @@ -328,79 +303,76 @@ void ClangLoopSwapping::initializeProviderOnServer() { [DIMTraitPoolServer](DIMemoryTraitPoolWrapper &Wrapper) { Wrapper.set(**DIMTraitPoolServer); }); - auto &GlobalsAAServer = R->value()->getResult(); - ClangLoopSwappingServerProvider::initialize( - [&GlobalsAAServer](GlobalsAAResultImmutableWrapper &Wrapper) { - Wrapper.set(GlobalsAAServer); - }); } -void ClangLoopSwapping::releaseMemory() { - mTfmCtx = nullptr; - DIDepInfo = nullptr; - DIAT = nullptr; - mGlobalOpts = nullptr; - mGlobalsAA = nullptr; - mSocket = nullptr; - mMemoryMatcher = nullptr; -} - -bool ClangLoopSwapping::IsNoLoopID(MDNode *LoopID) { - if (!LoopID || !(LoopID = getLoopID(LoopID))) { - dbgs() << "[LOOP SWAPPING]: ignore loop without ID."; - return true; - } - return false; -} - -std::vector ClangLoopSwapping::GetLoopNodes(MDNode *LoopID) { +std::vector ClangLoopSwapping::GetLoopTraits(MDNode *LoopID) { auto DepItr = DIDepInfo->find(LoopID); assert(DepItr != DIDepInfo->end() && "Loop must be analyzed!"); auto &DIDepSet = DepItr->get(); DenseSet Coverage; - auto tmp = mGlobalOpts->IgnoreRedundantMemory; - auto &tmp2 = *DIAT; - dbgs() << "Here1\n"; - accessCoverage(DIDepSet, tmp2, Coverage, - tmp); - dbgs() << "Here2\n"; - std::vector nodes; + accessCoverage(DIDepSet, *DIAT, Coverage, + mGlobalOpts->IgnoreRedundantMemory); + std::vector traits; for (auto &TS : DIDepSet) { auto node = TS.getNode(); - //TS.print(dbgs() << "[LOOP SWAPPING]: current node is: "); if (!Coverage.count(node)) continue; - MemoryDescriptor Dptr = TS; - if (Dptr.is()) { - dbgs() << "[LOOP SWAPPING]: readonly node found (" << TS.getNode() << ")\n"; - continue; - } - if (Dptr.is()) { - dbgs() << "[LOOP SWAPPING]: reduction node found (" << TS.getNode() << "); type: "; - auto I = TS.begin(), EI = TS.end(); - auto *Red = (**I).get(); - auto Kind = Red->getKind(); - if (!Red || Kind == trait::DIReduction::RK_NoReduction) { - dbgs() << "No Reduction\n"; - } else if (Kind == trait::DIReduction::RK_Add) { - dbgs() << "Add\n"; - } else if (Kind == trait::DIReduction::RK_Mult) { - dbgs() << "Mult\n"; + traits.push_back(&TS); + } + return traits; +} + +bool ClangLoopSwapping::HasSameReductionKind(std::vector &traits0, + std::vector &traits1, + SpanningTreeRelation &STR) { + for (auto TS0: traits0) { + auto *node0 = const_cast(TS0->getNode()); + MemoryDescriptor Dptr0 = *TS0; + for (auto TS1: traits1) { + auto *node1 = const_cast(TS1->getNode()); + MemoryDescriptor Dptr1 = *TS1; + if (STR.isEqual(node0, node1) && Dptr0.is() && + Dptr1.is()) { + dbgs() << "[LOOP SWAPPING]: same reduction nodes;\n"; + auto I0 = TS0->begin(), I1 = TS1->begin(); + auto *Red0 = (**I0).get(); + auto *Red1 = (**I1).get(); + auto Kind0 = Red0->getKind(), Kind1 = Red1->getKind(); + if (!Red0 || !Red1 || Kind0 == trait::DIReduction::RK_NoReduction || + Kind1 == trait::DIReduction::RK_NoReduction) { + dbgs() << "[LOOP SWAPPING]: No Reduction\n"; + return true; + } + if (Kind0 != Kind1) + return false; } - continue; - } - if (Dptr.is()) { - dbgs() << "[LOOP SWAPPING]: shared node found (" << TS.getNode() << ")\n"; - continue; } - if (TS.is()) { - dbgs() << "[LOOP SWAPPING]: induction node found (" << TS.getNode() << ")\n"; - continue; + } + return true; +} + +bool ClangLoopSwapping::HasTrueOrAntiDependence(std::vector &traits0, + std::vector &traits1, + SpanningTreeRelation &STR) { + for (auto TS0: traits0) { + auto *node0 = const_cast(TS0->getNode()); + MemoryDescriptor Dptr0 = *TS0; + for (auto TS1: traits1) { + auto *node1 = const_cast(TS1->getNode()); + MemoryDescriptor Dptr1 = *TS1; + if (STR.isEqual(node0, node1)) { + if (Dptr0.is() && !Dptr1.is()) { + dbgs() << "[LOOP SWAPPING]: anti dependence found;\n"; + return true; + } else if (Dptr1.is() && !Dptr0.is()) { + dbgs() << "[LOOP SWAPPING]: true dependence found;\n"; + return true; + } + } } - nodes.push_back(const_cast(node)); } - return nodes; + return false; } bool ClangLoopSwapping::IsSwappingAvailable(std::vector loops) { @@ -410,21 +382,29 @@ bool ClangLoopSwapping::IsSwappingAvailable(std::vector loops) { auto *Loop0_ID = loop0->getLoopID(); auto *Loop1_ID = loop1->getLoopID(); + if (!Loop0_ID || !(Loop0_ID = getLoopID(Loop0_ID))) { + dbgs() << "[LOOP SWAPPING]: ignore loop without ID (loop 0)."; + return false; + } - if (IsNoLoopID(Loop0_ID) || IsNoLoopID(Loop1_ID)) { - dbgs() << "[LOOP SWAPPING]: No loop ID.\n"; + if (!Loop1_ID || !(Loop1_ID = getLoopID(Loop1_ID))) { + dbgs() << "[LOOP SWAPPING]: ignore loop without ID (loop 1)."; return false; } - std::vector nodes0 = GetLoopNodes(Loop0_ID); - std::vector nodes1 = GetLoopNodes(Loop1_ID); + + std::vector traits0 = GetLoopTraits(Loop0_ID); + std::vector traits1 = GetLoopTraits(Loop1_ID); + SpanningTreeRelation STR(DIAT); - for (auto *node0: nodes0) { - for (auto *node1: nodes1) { - if (!STR.isUnreachable(node0, node1)) - return false; - } + + if (!HasSameReductionKind(traits0, traits1, STR)) { + dbgs() << "[LOOP SWAPPING]: Failed to swap loops: different reduction kinds."; + return false; + } + if (HasTrueOrAntiDependence(traits0, traits1, STR)) { + dbgs() << "[LOOP SWAPPING]: Failed to swap loops: true or anti depencende."; + return false; } - return true; } @@ -434,7 +414,6 @@ void ClangLoopSwapping::SwapLoops(const std::vector> &m for (int i = 0; i < mRangePairs.size(); i++) { std::vector ranges = mRangePairs[i]; std::vector loops = mLoopPairs[i]; - if (ranges.size() < 2) { dbgs() << "[LOOP SWAPPING]: Too few loops for swap. Ignore.\n"; continue; @@ -450,7 +429,7 @@ void ClangLoopSwapping::SwapLoops(const std::vector> &m mRewriter.ReplaceText(first, second_loop); mRewriter.ReplaceText(second, first_loop); } else { - dbgs() << "[LOOP SWAPPING]: Failed to swap loops: shared memory\n"; + dbgs() << " Loops will not be swapped.\n"; } } } @@ -487,7 +466,8 @@ bool ClangLoopSwapping::LoadDependenceAnalysisInfo(Function &F) { } bool ClangLoopSwapping::runOnFunction(Function &F) { - dbgs() << "test\n"; + mFunction = &F; + dbgs() << "\n[LOOP SWAPPING]: Function '" << F.getName() << "'.\n"; auto *M = F.getParent(); mTfmCtx = getAnalysis().getContext(*M); if (!mTfmCtx || !mTfmCtx->hasInstance()) { @@ -498,39 +478,33 @@ bool ClangLoopSwapping::runOnFunction(Function &F) { auto FuncDecl = mTfmCtx->getDeclForMangledName(F.getName()); if (!FuncDecl) return false; - mSocket = &getAnalysis().get(); - mMemoryMatcher = &getAnalysis().get(); mGlobalOpts = &getAnalysis().getOptions(); - mGlobalsAA = &getAnalysis().getResult(); - initializeProviderOnClient(*M); initializeProviderOnServer(); if (!LoadDependenceAnalysisInfo(F)) return false; - auto &mLoopInfo = getAnalysis().getMatcher(); LoopVisitor lv(mTfmCtx->getRewriter(), mLoopInfo); lv.TraverseDecl(FuncDecl); + if (lv.getLoopsCount() == 0) { + dbgs() << "[LOOP SWAPPING]: no loops found.\n"; + return false; + } lv.PrintLocations(); std::vector> mRangePairs = lv.getRangePairs(); std::vector> mLoopPairs = lv.getLoopPairs(); - - //auto &Provider = getAnalysis(F); SwapLoops(mRangePairs, mLoopPairs); return false; } void ClangLoopSwapping::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.addRequired(); AU.setPreservesAll(); @@ -552,11 +526,6 @@ char ClangLoopSwappingServer::ID = 0; INITIALIZE_PASS(ClangLoopSwappingServer, "clang-loop-swapping-server", "Loop Swapping (Clang, Server)", false, false) - -INITIALIZE_PROVIDER(ClangLoopSwappingProvider, - "clang-loop-swapping-provider", - "Loop Swapping (Clang, Provider)") - INITIALIZE_PASS_IN_GROUP_BEGIN(ClangLoopSwapping,"clang-l-swap", "'for' Loops Swapping (Clang)", false, false, tsar::TransformationQueryManager::getPassRegistry()); @@ -569,11 +538,7 @@ INITIALIZE_PASS_DEPENDENCY(DIEstimateMemoryPass); INITIALIZE_PASS_DEPENDENCY(GlobalOptionsImmutableWrapper); INITIALIZE_PASS_DEPENDENCY(DIMemoryEnvironmentWrapper); INITIALIZE_PASS_DEPENDENCY(DIMemoryTraitPoolWrapper); -INITIALIZE_PASS_DEPENDENCY(MemoryMatcherImmutableWrapper) -INITIALIZE_PASS_DEPENDENCY(ClangLoopSwappingProvider); INITIALIZE_PASS_DEPENDENCY(AnalysisSocketImmutableWrapper); -INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass); -INITIALIZE_PASS_DEPENDENCY(GlobalsAAResultImmutableWrapper); INITIALIZE_PASS_DEPENDENCY(ClangLoopSwappingServerProvider); INITIALIZE_PASS_DEPENDENCY(ClangLoopSwappingServerResponse); INITIALIZE_PASS_IN_GROUP_END(ClangLoopSwapping,"clang-l-swap", From 755eac2db762a2fc31a93652c173643e59775b4e Mon Sep 17 00:00:00 2001 From: Julia Lapenko Date: Sun, 27 Sep 2020 00:42:59 +0600 Subject: [PATCH 03/10] [TSAR, Transform] Fix invalid client-server interaction, fix incorrect comparison of reduction types. --- lib/Transform/Clang/LoopSwapping.cpp | 511 +++++++++++---------------- 1 file changed, 212 insertions(+), 299 deletions(-) diff --git a/lib/Transform/Clang/LoopSwapping.cpp b/lib/Transform/Clang/LoopSwapping.cpp index 5e5bfd3b..348acae5 100644 --- a/lib/Transform/Clang/LoopSwapping.cpp +++ b/lib/Transform/Clang/LoopSwapping.cpp @@ -22,35 +22,24 @@ // //===----------------------------------------------------------------------===// -#include "tsar/ADT/SpanningTreeRelation.h" #include "tsar/Analysis/AnalysisServer.h" -#include "tsar/Transform/Clang/LoopSwapping.h" -#include "tsar/Analysis/Clang/GlobalInfoExtractor.h" #include "tsar/Analysis/Clang/LoopMatcher.h" #include "tsar/Analysis/Clang/NoMacroAssert.h" -#include "tsar/Analysis/Clang/SourceLocationTraverse.h" #include "tsar/Analysis/Memory/DIDependencyAnalysis.h" #include "tsar/Analysis/Memory/DIEstimateMemory.h" #include "tsar/Analysis/Memory/MemoryTraitUtils.h" -#include "tsar/Analysis/Memory/ServerUtils.h" -#include "tsar/Core/Query.h" #include "tsar/Core/TransformationContext.h" +#include "tsar/Core/Query.h" +#include "tsar/Frontend/Clang/Pragma.h" #include "tsar/Support/Clang/Diagnostic.h" -#include "tsar/Support/Clang/Pragma.h" +#include "tsar/Support/Clang/SourceLocationTraverse.h" #include "tsar/Support/GlobalOptions.h" #include "tsar/Support/PassAAProvider.h" -#include +#include "tsar/Support/Tags.h" +#include "tsar/Transform/Clang/Passes.h" #include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include - using namespace llvm; using namespace clang; @@ -59,98 +48,48 @@ using namespace tsar; #undef DEBUG_TYPE #define DEBUG_TYPE "clang-l-swap" -char ClangLoopSwapping::ID = 0; - -namespace llvm { - -static void initializeClangLoopSwappingServerPass(PassRegistry &); -static void initializeClangLoopSwappingServerResponsePass(PassRegistry &); - -} - namespace { /// This provides access to function-level analysis results on server. -using ClangLoopSwappingServerProvider = +using ClangLoopSwappingProvider = FunctionPassAAProvider; -/// List of responses available from server (client may request corresponding -/// analysis, in case of provider all analysis related to a provider may -/// be requested separately). -using ClangLoopSwappingServerResponse = AnalysisResponsePass< - DIMemoryTraitPoolWrapper, DIMemoryEnvironmentWrapper, - ClangLoopSwappingServerProvider>; +using RangeVector = SmallVector; -/// This analysis server performs transformation-based analysis. -class ClangLoopSwappingServer final : public AnalysisServer { -public: - static char ID; - ClangLoopSwappingServer() : AnalysisServer(ID) { - initializeClangLoopSwappingServerPass(*PassRegistry::getPassRegistry()); - } +using RangePairVector = std::vector; - void getAnalysisUsage(AnalysisUsage &AU) const override { - AnalysisServer::getAnalysisUsage(AU); - ClientToServerMemory::getAnalysisUsage(AU); - AU.addRequired(); - } +using LoopVector = SmallVector; - void prepareToClone(llvm::Module &ClientM, - ValueToValueMapTy &ClientToServer) override { - ClientToServerMemory::prepareToClone(ClientM, ClientToServer); - } +using LoopPairVector = std::vector; - void initializeServer(llvm::Module &CM, llvm::Module &SM, ValueToValueMapTy &CToS, - legacy::PassManager &PM) override { - auto &GO = getAnalysis(); - PM.add(createGlobalOptionsImmutableWrapper(&GO.getOptions())); - PM.add(createDIMemoryTraitPoolStorage()); - ClientToServerMemory::initializeServer(*this, CM, SM, CToS, PM); - } - - void addServerPasses(llvm::Module &M, legacy::PassManager &PM) override { - auto &GO = getAnalysis().getOptions(); - addImmutableAliasAnalysis(PM); - addBeforeTfmAnalysis(PM); - addAfterSROAAnalysis(GO, M.getDataLayout(), PM); - addAfterLoopRotateAnalysis(PM); - PM.add(createVerifierPass()); - PM.add(new ClangLoopSwappingServerResponse); - } - - void prepareToClose(legacy::PassManager &PM) override { - ClientToServerMemory::prepareToClose(PM); - } -}; +using DIAliasTraitVector = std::vector; class LoopVisitor : public RecursiveASTVisitor { +private: + enum TraverseState { NONE, PRAGMA, OUTERFOR, INNERFOR }; public: - LoopVisitor(Rewriter &Rewr, const LoopMatcherPass::LoopMatcher &LM) : - mRewriter(Rewr), - mLoopInfo(LM), - mSrcMgr(Rewr.getSourceMgr()), - mLangOpts(Rewr.getLangOpts()), - mIsInScope(false), mForStack(nullptr) - {} + LoopVisitor(Rewriter &Rewr, const LoopMatcherPass::LoopMatcher &LM, + const ASTImportInfo &ImportInfo) + : mRewriter(Rewr) + , mSrcMgr(Rewr.getSourceMgr()) + , mImportInfo(ImportInfo) + , mLangOpts(Rewr.getLangOpts()) + , mLoopInfo(LM) + , mState(TraverseState::NONE) + {} void EnterInScope() { mForLocations.clear(); mForIRs.clear(); - mIsInScope = true; } void ExitFromScope() { mForLocations.clear(); mForIRs.clear(); - mIsInScope = false; - } - - bool IsInScope() { - return mIsInScope; } bool TraverseStmt(Stmt *S) { - if (!S) + if (!S) return true; Pragma P(*S); if (P) { @@ -158,16 +97,17 @@ class LoopVisitor : public RecursiveASTVisitor { if (findClause(P, ClauseId::SwapLoops, mClauses)) { llvm::SmallVector ToRemove; auto IsPossible = - pragmaRangeToRemove(P, mClauses, mSrcMgr, mLangOpts, ToRemove); + pragmaRangeToRemove(P, mClauses, mSrcMgr, mLangOpts, mImportInfo, + ToRemove); if (!IsPossible.first) if (IsPossible.second & PragmaFlags::IsInMacro) - toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getLocStart(), + toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), diag::warn_remove_directive_in_macro); else if (IsPossible.second & PragmaFlags::IsInHeader) - toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getLocStart(), + toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), diag::warn_remove_directive_in_include); else - toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getLocStart(), + toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), diag::warn_remove_directive); Rewriter::RewriteOptions RemoveEmptyLine; /// TODO (kaniandr@gmail.com): it seems that RemoveLineIfEmpty is @@ -175,77 +115,73 @@ class LoopVisitor : public RecursiveASTVisitor { RemoveEmptyLine.RemoveLineIfEmpty = false; for (auto SR : ToRemove) mRewriter.RemoveText(SR, RemoveEmptyLine); + mState = TraverseState::PRAGMA; EnterInScope(); } return true; - } - auto Res = RecursiveASTVisitor::TraverseStmt(S); + } + auto Res = RecursiveASTVisitor::TraverseStmt(S); return Res; } bool TraverseCompoundStmt(CompoundStmt *S) { - if (IsInScope() && mForStack == nullptr) { - mForStack = new std::stack; + if (mState == TraverseState::PRAGMA) { + mState = TraverseState::OUTERFOR; mForLocations.clear(); mForIRs.clear(); auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S); - while (!mForStack->empty()) - mForStack->pop(); - delete mForStack; - mForStack = nullptr; + mState = TraverseState::PRAGMA; mRangePairs.push_back(mForLocations); mLoopPairs.push_back(mForIRs); ExitFromScope(); return Res; } - return RecursiveASTVisitor::TraverseCompoundStmt(S); + return RecursiveASTVisitor::TraverseCompoundStmt(S); } bool TraverseForStmt(ForStmt *S) { - if (IsInScope() && mForStack != nullptr) { - if (mForStack->empty()) { - auto Match = mLoopInfo.find(S); - if (Match != mLoopInfo.end()) { - Loop *loop = Match->get(); - mForIRs.push_back(loop); - SourceRange range(S->getBeginLoc(), S->getEndLoc()); - mForLocations.push_back(range); - } - mForStack->push(S); - auto Res = RecursiveASTVisitor::TraverseForStmt(S); - mForStack->pop(); - return Res; - } - } + if (mState == TraverseState::OUTERFOR) { + auto Match = mLoopInfo.find(S); + if (Match != mLoopInfo.end()) { + Loop *MatchLoop = Match->get(); + mForIRs.push_back(MatchLoop); + SourceRange Range(S->getBeginLoc(), S->getEndLoc()); + mForLocations.push_back(Range); + } + mState = TraverseState::INNERFOR; + auto Res = RecursiveASTVisitor::TraverseForStmt(S); + mState = TraverseState::OUTERFOR; + return Res; + } return RecursiveASTVisitor::TraverseForStmt(S); } - std::vector> getRangePairs() { + RangePairVector getRangePairs() const { return mRangePairs; } - std::vector> getLoopPairs() { + LoopPairVector getLoopPairs() const { return mLoopPairs; } - size_t getLoopsCount() { + size_t getLoopCount() const { return mRangePairs.size(); } - void PrintLocations() { - dbgs() << "[LOOP SWAPPING]: 'for' loop locations:\n"; - unsigned int loopNumber = 0; + void printLocations() const { + LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: 'for' loop locations:\n"); + size_t LoopNumber = 0; for (auto locs: mRangePairs) { for (auto location : locs) { - dbgs() << "Loop #" << loopNumber << ":\n"; - SourceLocation begin = location.getBegin(); - SourceLocation end = location.getEnd(); - dbgs() << "\tBegin: "; - begin.print(dbgs(), mSrcMgr); - dbgs() << "\n\tEnd: "; - end.print(dbgs(), mSrcMgr); - dbgs() << '\n'; - loopNumber++; + LLVM_DEBUG(dbgs() << "Loop #" << LoopNumber << ":\n"); + SourceLocation Begin = location.getBegin(); + SourceLocation End = location.getEnd(); + LLVM_DEBUG(dbgs() << "\tBegin: "); + Begin.print(dbgs(), mSrcMgr); + LLVM_DEBUG(dbgs() << "\n\tEnd: "); + End.print(dbgs(), mSrcMgr); + LLVM_DEBUG(dbgs() << '\n'); + LoopNumber++; } } } @@ -253,16 +189,44 @@ class LoopVisitor : public RecursiveASTVisitor { private: Rewriter &mRewriter; SourceManager &mSrcMgr; + const ASTImportInfo &mImportInfo; const LangOptions &mLangOpts; - bool mIsInScope; const LoopMatcherPass::LoopMatcher &mLoopInfo; - + TraverseState mState; SmallVector mClauses; - std::vector mForLocations; - std::vector mForIRs; - std::vector> mRangePairs; - std::vector> mLoopPairs; - std::stack *mForStack; + RangeVector mForLocations; + LoopVector mForIRs; + RangePairVector mRangePairs; + LoopPairVector mLoopPairs; +}; + +class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { +public: + static char ID; + + ClangLoopSwapping() : FunctionPass(ID) { + initializeClangLoopSwappingPass(*PassRegistry::getPassRegistry()); + } + bool runOnFunction(Function &F) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; + +private: + void swapLoops(const LoopVisitor &Visitor); + DIAliasTraitVector getLoopTraits(MDNode *LoopID) const; + bool isSwappingAvailable(const LoopVector &Loops) const; + bool hasSameReductionKind(const DIAliasTraitVector &TV0, + const DIAliasTraitVector &TV1) const; + bool hasTrueOrAntiDependence(const DIAliasTraitVector &TV0, + const DIAliasTraitVector &TV1) const; + + Function *mFunction = nullptr; + TransformationContext *mTfmCtx = nullptr; + const GlobalOptions *mGlobalOpts = nullptr; + AnalysisSocketInfo *mSocketInfo = nullptr; + DIDependencInfo *mDIDepInfo = nullptr; + DIAliasTree *mDIAT = nullptr; + std::function mGetLoopID; + const SourceManager *mSrcMgr = nullptr; }; class ClangLoopSwappingInfo final : public PassGroupInfo { @@ -273,7 +237,8 @@ class ClangLoopSwappingInfo final : public PassGroupInfo { Passes.add(createDIMemoryTraitPoolStorage()); Passes.add(createDIMemoryEnvironmentStorage()); Passes.add(createDIEstimateMemoryPass()); - Passes.add(new ClangLoopSwappingServer); + Passes.add(createDIMemoryAnalysisServer()); + Passes.add(createAnalysisWaitServerPass()); Passes.add(createAnalysisWaitServerPass()); } @@ -283,66 +248,50 @@ class ClangLoopSwappingInfo final : public PassGroupInfo { } }; -} +} //namespace -void ClangLoopSwapping::initializeProviderOnServer() { - ClangLoopSwappingServerProvider::initialize( - [this](GlobalOptionsImmutableWrapper &Wrapper) { - Wrapper.setOptions(mGlobalOpts); - }); - auto R = mSocket->getAnalysis< - DIMemoryEnvironmentWrapper, DIMemoryTraitPoolWrapper>(); - assert(R && "Immutable passes must be available on server!"); - auto *DIMEnvServer = R->value(); - ClangLoopSwappingServerProvider::initialize( - [DIMEnvServer](DIMemoryEnvironmentWrapper &Wrapper) { - Wrapper.set(**DIMEnvServer); - }); - auto *DIMTraitPoolServer = R->value(); - ClangLoopSwappingServerProvider::initialize( - [DIMTraitPoolServer](DIMemoryTraitPoolWrapper &Wrapper) { - Wrapper.set(**DIMTraitPoolServer); - }); - -} +char ClangLoopSwapping::ID = 0; -std::vector ClangLoopSwapping::GetLoopTraits(MDNode *LoopID) { - auto DepItr = DIDepInfo->find(LoopID); - assert(DepItr != DIDepInfo->end() && "Loop must be analyzed!"); +DIAliasTraitVector ClangLoopSwapping::getLoopTraits(MDNode *LoopID) const { + auto DepItr = mDIDepInfo->find(LoopID); + assert(DepItr != mDIDepInfo->end() && "Loop must be analyzed!"); auto &DIDepSet = DepItr->get(); DenseSet Coverage; - accessCoverage(DIDepSet, *DIAT, Coverage, + accessCoverage(DIDepSet, *mDIAT, Coverage, mGlobalOpts->IgnoreRedundantMemory); - std::vector traits; + DIAliasTraitVector Traits; for (auto &TS : DIDepSet) { - auto node = TS.getNode(); - if (!Coverage.count(node)) + if (!Coverage.count(TS.getNode())) continue; - traits.push_back(&TS); + Traits.push_back(&TS); } - return traits; + return Traits; } -bool ClangLoopSwapping::HasSameReductionKind(std::vector &traits0, - std::vector &traits1, - SpanningTreeRelation &STR) { - for (auto TS0: traits0) { - auto *node0 = const_cast(TS0->getNode()); +bool ClangLoopSwapping::hasSameReductionKind( + const DIAliasTraitVector &TV0, const DIAliasTraitVector &TV1) const { + for (auto &TS0: TV0) { + auto *Node0 = TS0->getNode(); MemoryDescriptor Dptr0 = *TS0; - for (auto TS1: traits1) { - auto *node1 = const_cast(TS1->getNode()); + if (!Dptr0.is()) + continue; + for (auto &TS1: TV1) { + auto *Node1 = TS1->getNode(); MemoryDescriptor Dptr1 = *TS1; - if (STR.isEqual(node0, node1) && Dptr0.is() && - Dptr1.is()) { - dbgs() << "[LOOP SWAPPING]: same reduction nodes;\n"; + if (Node0 == Node1 && Dptr1.is()) { + LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: Same nodes with reduction.\n"); auto I0 = TS0->begin(), I1 = TS1->begin(); auto *Red0 = (**I0).get(); auto *Red1 = (**I1).get(); + if (!Red0 || !Red1) { + LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: Unknown Reduction.\n"); + return false; + } auto Kind0 = Red0->getKind(), Kind1 = Red1->getKind(); - if (!Red0 || !Red1 || Kind0 == trait::DIReduction::RK_NoReduction || + if (Kind0 == trait::DIReduction::RK_NoReduction || Kind1 == trait::DIReduction::RK_NoReduction) { - dbgs() << "[LOOP SWAPPING]: No Reduction\n"; - return true; + LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: Unknown Reduction.\n"); + return false; } if (Kind0 != Kind1) return false; @@ -352,21 +301,20 @@ bool ClangLoopSwapping::HasSameReductionKind(std::vector & return true; } -bool ClangLoopSwapping::HasTrueOrAntiDependence(std::vector &traits0, - std::vector &traits1, - SpanningTreeRelation &STR) { - for (auto TS0: traits0) { - auto *node0 = const_cast(TS0->getNode()); +bool ClangLoopSwapping::hasTrueOrAntiDependence( + const DIAliasTraitVector &TV0, const DIAliasTraitVector &TV1) const { + for (auto &TS0: TV0) { + auto *Node0 = TS0->getNode(); MemoryDescriptor Dptr0 = *TS0; - for (auto TS1: traits1) { - auto *node1 = const_cast(TS1->getNode()); + for (auto &TS1: TV1) { + auto *Node1 = TS1->getNode(); MemoryDescriptor Dptr1 = *TS1; - if (STR.isEqual(node0, node1)) { + if (Node0 == Node1) { if (Dptr0.is() && !Dptr1.is()) { - dbgs() << "[LOOP SWAPPING]: anti dependence found;\n"; + // anti dependence return true; - } else if (Dptr1.is() && !Dptr0.is()) { - dbgs() << "[LOOP SWAPPING]: true dependence found;\n"; + } else if (Dptr1.is() && !Dptr0.is()){ + // true dependence return true; } } @@ -375,99 +323,64 @@ bool ClangLoopSwapping::HasTrueOrAntiDependence(std::vector loops) { - Loop *loop0 = loops[0]; - Loop *loop1 = loops[1]; - - auto *Loop0_ID = loop0->getLoopID(); - auto *Loop1_ID = loop1->getLoopID(); - - if (!Loop0_ID || !(Loop0_ID = getLoopID(Loop0_ID))) { - dbgs() << "[LOOP SWAPPING]: ignore loop without ID (loop 0)."; +bool ClangLoopSwapping::isSwappingAvailable(const LoopVector &Loops) const { + auto HasLoopID = [this](MDNode*& LoopID, int LoopN) { + if (!LoopID || !(LoopID = mGetLoopID(LoopID))) { + LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: ignore loop without ID (loop " << + LoopN << ")."); + return false; + } + return true; + }; + auto *LoopID0 = Loops[0]->getLoopID(); + auto *LoopID1 = Loops[1]->getLoopID(); + if (!HasLoopID(LoopID0, 0)) return false; - } - - if (!Loop1_ID || !(Loop1_ID = getLoopID(Loop1_ID))) { - dbgs() << "[LOOP SWAPPING]: ignore loop without ID (loop 1)."; + if (!HasLoopID(LoopID1, 1)) return false; - } - - std::vector traits0 = GetLoopTraits(Loop0_ID); - std::vector traits1 = GetLoopTraits(Loop1_ID); - - SpanningTreeRelation STR(DIAT); - - if (!HasSameReductionKind(traits0, traits1, STR)) { - dbgs() << "[LOOP SWAPPING]: Failed to swap loops: different reduction kinds."; + auto Traits0 = getLoopTraits(LoopID0); + auto Traits1 = getLoopTraits(LoopID1); + if (!hasSameReductionKind(Traits0, Traits1)) { + toDiag(mSrcMgr->getDiagnostics(), diag::warn_loop_swapping_diff_reduction); return false; } - if (HasTrueOrAntiDependence(traits0, traits1, STR)) { - dbgs() << "[LOOP SWAPPING]: Failed to swap loops: true or anti depencende."; + if (hasTrueOrAntiDependence(Traits0, Traits1)) { + toDiag(mSrcMgr->getDiagnostics(), + diag::warn_loop_swapping_true_anti_dependence); return false; } return true; } -void ClangLoopSwapping::SwapLoops(const std::vector> &mRangePairs, - const std::vector> &mLoopPairs) { +void ClangLoopSwapping::swapLoops(const LoopVisitor &Visitor) { + const auto &RangePairs = Visitor.getRangePairs(); + const auto &LoopPairs = Visitor.getLoopPairs(); Rewriter &mRewriter = mTfmCtx->getRewriter(); - for (int i = 0; i < mRangePairs.size(); i++) { - std::vector ranges = mRangePairs[i]; - std::vector loops = mLoopPairs[i]; - if (ranges.size() < 2) { - dbgs() << "[LOOP SWAPPING]: Too few loops for swap. Ignore.\n"; + for (size_t i = 0; i < RangePairs.size(); i++) { + const auto &Ranges = RangePairs[i]; + const auto &Loops = LoopPairs[i]; + if (Ranges.size() < 2) { + toDiag(mSrcMgr->getDiagnostics(), + diag::warn_loop_swapping_missing_loop); continue; } - if (ranges.size() > 2) { - dbgs() << "[LOOP SWAPPING]: Too many loops for swap. Ignore additional loops.\n"; + if (Ranges.size() > 2) { + toDiag(mSrcMgr->getDiagnostics(), + diag::warn_loop_swapping_redundant_loop); } - if (IsSwappingAvailable(loops)) { - SourceRange first = ranges[0]; - SourceRange second = ranges[1]; - std::string first_loop = mRewriter.getRewrittenText(first); - std::string second_loop = mRewriter.getRewrittenText(second); - mRewriter.ReplaceText(first, second_loop); - mRewriter.ReplaceText(second, first_loop); - } else { - dbgs() << " Loops will not be swapped.\n"; + if (isSwappingAvailable(Loops)) { + const auto &FirstRange = Ranges[0]; + const auto &SecondRange = Ranges[1]; + const auto &FirstLoop = mRewriter.getRewrittenText(FirstRange); + const auto &SecondLoop = mRewriter.getRewrittenText(SecondRange); + mRewriter.ReplaceText(FirstRange, SecondLoop); + mRewriter.ReplaceText(SecondRange, FirstLoop); } } } -bool ClangLoopSwapping::LoadDependenceAnalysisInfo(Function &F) { - getLoopID = [](ObjectID ID) { return ID; }; - if (auto *Socket = getAnalysisIfAvailable()) { - if (auto R = (*Socket)->getAnalysis()) { - auto *Matcher = R->value(); - getLoopID = [Matcher](ObjectID ID) { - auto ServerID = (*Matcher)->getMappedMD(ID); - return ServerID ? cast(*ServerID) : nullptr; - }; - if (auto R =(*Socket)->getAnalysis< - DIEstimateMemoryPass, DIDependencyAnalysisPass>(F)) { - DIAT = &R->value()->getAliasTree(); - DIDepInfo = &R->value()->getDependencies(); - } - } - } - if (!DIAT || !DIDepInfo) { - dbgs() << "[LOOP SWAPPING]: analysis server is not available\n"; - if (auto *P = getAnalysisIfAvailable()) - DIAT = &P->getAliasTree(); - else - return false; - if (auto *P = getAnalysisIfAvailable()) - DIDepInfo = &P->getDependencies(); - else - return false; - dbgs() << "[LOOP SWAPPING]: use dependence analysis from client\n"; - } - return true; -} - bool ClangLoopSwapping::runOnFunction(Function &F) { mFunction = &F; - dbgs() << "\n[LOOP SWAPPING]: Function '" << F.getName() << "'.\n"; auto *M = F.getParent(); mTfmCtx = getAnalysis().getContext(*M); if (!mTfmCtx || !mTfmCtx->hasInstance()) { @@ -478,35 +391,44 @@ bool ClangLoopSwapping::runOnFunction(Function &F) { auto FuncDecl = mTfmCtx->getDeclForMangledName(F.getName()); if (!FuncDecl) return false; - mSocket = &getAnalysis().get(); + mSocketInfo = &getAnalysis().get(); mGlobalOpts = &getAnalysis().getOptions(); - initializeProviderOnServer(); - if (!LoadDependenceAnalysisInfo(F)) - return false; + auto *Socket = mSocketInfo->getActiveSocket(); + auto RF = + Socket->getAnalysis(F); + assert(RF && "Dependence analysis must be available for a parallel loop!"); + mDIAT = &RF->value()->getAliasTree(); + mDIDepInfo = &RF->value()->getDependencies(); + auto R = Socket->getAnalysis(); + auto *Matcher = R->value(); + mGetLoopID = [Matcher](ObjectID ID) { + auto ServerID = (*Matcher)->getMappedMD(ID); + return ServerID ? cast(*ServerID) : nullptr; + }; auto &mLoopInfo = getAnalysis().getMatcher(); - LoopVisitor lv(mTfmCtx->getRewriter(), mLoopInfo); - lv.TraverseDecl(FuncDecl); - if (lv.getLoopsCount() == 0) { - dbgs() << "[LOOP SWAPPING]: no loops found.\n"; + ASTImportInfo ImportStub; + const auto *ImportInfo = &ImportStub; + if (auto *ImportPass = getAnalysisIfAvailable()) + ImportInfo = &ImportPass->getImportInfo(); + LoopVisitor Visitor(mTfmCtx->getRewriter(), mLoopInfo, *ImportInfo); + mSrcMgr = &mTfmCtx->getRewriter().getSourceMgr(); + Visitor.TraverseDecl(FuncDecl); + if (Visitor.getLoopCount() == 0) { + LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: no loop found.\n"); return false; } - lv.PrintLocations(); - std::vector> mRangePairs = lv.getRangePairs(); - std::vector> mLoopPairs = lv.getLoopPairs(); - SwapLoops(mRangePairs, mLoopPairs); + Visitor.printLocations(); + swapLoops(Visitor); return false; } void ClangLoopSwapping::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); - AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addRequired(); - AU.addRequired(); - AU.addRequired(); AU.setPreservesAll(); } @@ -514,33 +436,24 @@ FunctionPass * llvm::createClangLoopSwapping() { return new ClangLoopSwapping(); } -INITIALIZE_PROVIDER(ClangLoopSwappingServerProvider, "clang-loop-swapping-server-provider", - "Loop Swapping (Clang, Server, Provider)") - -template <> char ClangLoopSwappingServerResponse::ID = 0; -INITIALIZE_PASS(ClangLoopSwappingServerResponse, "clang-loop-swapping-response", - "Loop Swapping (Clang, Server, Response)", true, - false) - -char ClangLoopSwappingServer::ID = 0; -INITIALIZE_PASS(ClangLoopSwappingServer, "clang-loop-swapping-server", - "Loop Swapping (Clang, Server)", false, false) - +INITIALIZE_PROVIDER_BEGIN(ClangLoopSwappingProvider, + "clang-loop-swapping-provider", + "Loop Swapping (Clang, Provider)"); +INITIALIZE_PASS_DEPENDENCY(DIDependencyAnalysisPass); +INITIALIZE_PASS_DEPENDENCY(DIEstimateMemoryPass); +INITIALIZE_PROVIDER_END(ClangLoopSwappingProvider, + "clang-loop-swapping-provider", + "Loop Swapping (Clang, Provider)"); + INITIALIZE_PASS_IN_GROUP_BEGIN(ClangLoopSwapping,"clang-l-swap", "'for' Loops Swapping (Clang)", false, false, tsar::TransformationQueryManager::getPassRegistry()); INITIALIZE_PASS_IN_GROUP_INFO(ClangLoopSwappingInfo); +INITIALIZE_PASS_DEPENDENCY(AnalysisSocketImmutableWrapper); INITIALIZE_PASS_DEPENDENCY(TransformationEnginePass); INITIALIZE_PASS_DEPENDENCY(LoopMatcherPass); -INITIALIZE_PASS_DEPENDENCY(ClangGlobalInfoPass); -INITIALIZE_PASS_DEPENDENCY(DIDependencyAnalysisPass); -INITIALIZE_PASS_DEPENDENCY(DIEstimateMemoryPass); INITIALIZE_PASS_DEPENDENCY(GlobalOptionsImmutableWrapper); -INITIALIZE_PASS_DEPENDENCY(DIMemoryEnvironmentWrapper); -INITIALIZE_PASS_DEPENDENCY(DIMemoryTraitPoolWrapper); -INITIALIZE_PASS_DEPENDENCY(AnalysisSocketImmutableWrapper); -INITIALIZE_PASS_DEPENDENCY(ClangLoopSwappingServerProvider); -INITIALIZE_PASS_DEPENDENCY(ClangLoopSwappingServerResponse); +INITIALIZE_PASS_DEPENDENCY(ClangLoopSwappingProvider); INITIALIZE_PASS_IN_GROUP_END(ClangLoopSwapping,"clang-l-swap", "'for' Loops Swapping (Clang)", false, false, tsar::TransformationQueryManager::getPassRegistry()); \ No newline at end of file From db422bee3eff583b15ef3b53a8c886120545ac9c Mon Sep 17 00:00:00 2001 From: Julia Lapenko Date: Tue, 29 Sep 2020 21:48:09 +0600 Subject: [PATCH 04/10] [TSAR, Transform] Add handling of nested pragmas. --- include/tsar/Support/DiagnosticKinds.td | 5 + include/tsar/Transform/Clang/LoopSwapping.h | 91 ---------- include/tsar/Transform/Clang/Passes.h | 2 +- lib/Transform/Clang/LoopSwapping.cpp | 183 +++++++++++--------- 4 files changed, 109 insertions(+), 172 deletions(-) delete mode 100644 include/tsar/Transform/Clang/LoopSwapping.h diff --git a/include/tsar/Support/DiagnosticKinds.td b/include/tsar/Support/DiagnosticKinds.td index 4b57f059..5058cac2 100644 --- a/include/tsar/Support/DiagnosticKinds.td +++ b/include/tsar/Support/DiagnosticKinds.td @@ -179,3 +179,8 @@ def error_expect_function_param : Error<"expected function parameter name">; def note_record_member_unknown: Error<"record has no member '%0'">; def note_declared_here: Note<"declared here">; + +def warn_loop_swapping_diff_reduction: Warning<"unable to swap loops due to the different reduction types">; +def warn_loop_swapping_true_anti_dependence: Warning<"unable to swap loops due to the true or anti dependence">; +def warn_loop_swapping_missing_loop: Warning<"not enough loops for swapping">; +def warn_loop_swapping_redundant_loop: Warning<"too many loops for swapping, ignore redundant">; diff --git a/include/tsar/Transform/Clang/LoopSwapping.h b/include/tsar/Transform/Clang/LoopSwapping.h deleted file mode 100644 index 397916e2..00000000 --- a/include/tsar/Transform/Clang/LoopSwapping.h +++ /dev/null @@ -1,91 +0,0 @@ -//=== LoopSwapping.h - Loop Swapping (Clang) ----*- C++ -*===// -// -// Traits Static Analyzer (SAPFOR) -// -// Copyright 2018 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. -// -//===---------------------------------------------------------------------===// -// -// The file declares a pass to perform swapping of specific loops. -// -//===---------------------------------------------------------------------===// - -#ifndef TSAR_CLANG_LOOP_SWAPPING_H -#define TSAR_CLANG_LOOP_SWAPPING_H - -#include "tsar/Support/Tags.h" -#include "tsar/Transform/Clang/Passes.h" -#include "tsar/Analysis/AnalysisServer.h" -#include "tsar/Analysis/Memory/DIDependencyAnalysis.h" -#include "tsar/Support/GlobalOptions.h" -#include -#include - -namespace tsar { - class TransformationContext; - class DIAliasNode; - class DIAliasTree; -} - -namespace clang { - class SourceRange; - class Rewriter; -} - -namespace llvm { - -class Loop; -class MDNode; - -class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { -public: - static char ID; - - ClangLoopSwapping() : FunctionPass(ID) { - initializeClangLoopSwappingPass(*PassRegistry::getPassRegistry()); - } - bool runOnFunction(Function &F) override; - void getAnalysisUsage(AnalysisUsage &AU) const override; - void releaseMemory() override; - -private: - void initializeProviderOnServer(); - - bool LoadDependenceAnalysisInfo(Function &F); - void SwapLoops(const std::vector> &mRangePairs, - const std::vector> &mLoopPairs); - std::vector GetLoopTraits(llvm::MDNode *LoopID); - tsar::DIDependenceSet &GetLoopDepSet(MDNode *LoopID); - bool IsSwappingAvailable(std::vector loops); - - bool HasSameReductionKind(std::vector &traits0, - std::vector &traits1, - tsar::SpanningTreeRelation &STR); - bool HasTrueOrAntiDependence(std::vector &traits0, - std::vector &traits1, - tsar::SpanningTreeRelation &STR); - - llvm::Function *mFunction = nullptr; - tsar::TransformationContext *mTfmCtx = nullptr; - tsar::DIDependencInfo *DIDepInfo = nullptr; - tsar::DIAliasTree *DIAT = nullptr; - const tsar::GlobalOptions *mGlobalOpts = nullptr; - tsar::AnalysisSocket *mSocket = nullptr; - std::function getLoopID; -}; - -} - -#endif//TSAR_CLANG_LOOP_SWAPPING_H diff --git a/include/tsar/Transform/Clang/Passes.h b/include/tsar/Transform/Clang/Passes.h index ba106472..c6ef10d3 100644 --- a/include/tsar/Transform/Clang/Passes.h +++ b/include/tsar/Transform/Clang/Passes.h @@ -92,7 +92,7 @@ ModulePass * createClangStructureReplacementPass(); /// Initialize a pass to perform replacement of access to structure fields /// with separate variables. void initializeClangStructureReplacementPassPass(PassRegistry &Registry); -} + /// Creates a pass to perform swapping of loops. FunctionPass * createClangLoopSwapping(); diff --git a/lib/Transform/Clang/LoopSwapping.cpp b/lib/Transform/Clang/LoopSwapping.cpp index 348acae5..aaa857cc 100644 --- a/lib/Transform/Clang/LoopSwapping.cpp +++ b/lib/Transform/Clang/LoopSwapping.cpp @@ -32,14 +32,17 @@ #include "tsar/Core/Query.h" #include "tsar/Frontend/Clang/Pragma.h" #include "tsar/Support/Clang/Diagnostic.h" +#include "tsar/Support/Clang/Utils.h" #include "tsar/Support/Clang/SourceLocationTraverse.h" #include "tsar/Support/GlobalOptions.h" #include "tsar/Support/PassAAProvider.h" #include "tsar/Support/Tags.h" #include "tsar/Transform/Clang/Passes.h" #include +#include #include #include +#include using namespace llvm; using namespace clang; @@ -53,16 +56,9 @@ namespace { /// This provides access to function-level analysis results on server. using ClangLoopSwappingProvider = FunctionPassAAProvider; - -using RangeVector = SmallVector; - -using RangePairVector = std::vector; - -using LoopVector = SmallVector; - -using LoopPairVector = std::vector; - using DIAliasTraitVector = std::vector; +using LoopRangeInfo = std::pair; +using LoopRangeVector = SmallVector; class LoopVisitor : public RecursiveASTVisitor { private: @@ -76,18 +72,9 @@ class LoopVisitor : public RecursiveASTVisitor { , mLangOpts(Rewr.getLangOpts()) , mLoopInfo(LM) , mState(TraverseState::NONE) + , mCurrentLevel(-1) {} - void EnterInScope() { - mForLocations.clear(); - mForIRs.clear(); - } - - void ExitFromScope() { - mForLocations.clear(); - mForIRs.clear(); - } - bool TraverseStmt(Stmt *S) { if (!S) return true; @@ -95,7 +82,7 @@ class LoopVisitor : public RecursiveASTVisitor { if (P) { // Search for loop swapping clause and disable renaming in other pragmas. if (findClause(P, ClauseId::SwapLoops, mClauses)) { - llvm::SmallVector ToRemove; + SmallVector ToRemove; auto IsPossible = pragmaRangeToRemove(P, mClauses, mSrcMgr, mLangOpts, mImportInfo, ToRemove); @@ -115,8 +102,12 @@ class LoopVisitor : public RecursiveASTVisitor { RemoveEmptyLine.RemoveLineIfEmpty = false; for (auto SR : ToRemove) mRewriter.RemoveText(SR, RemoveEmptyLine); + mCurrentLevel++; + if (mCurrentLevel + 1 > int(mPragmaLevels.size())) { + mPragmaLevels.resize(mCurrentLevel + 1); + } + mPragmaLevels[mCurrentLevel].push_back(S); mState = TraverseState::PRAGMA; - EnterInScope(); } return true; } @@ -127,13 +118,12 @@ class LoopVisitor : public RecursiveASTVisitor { bool TraverseCompoundStmt(CompoundStmt *S) { if (mState == TraverseState::PRAGMA) { mState = TraverseState::OUTERFOR; - mForLocations.clear(); - mForIRs.clear(); + mLoopStack.push(LoopRangeVector()); auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S); mState = TraverseState::PRAGMA; - mRangePairs.push_back(mForLocations); - mLoopPairs.push_back(mForIRs); - ExitFromScope(); + mPragmaLoopsInfo[mPragmaLevels[mCurrentLevel].back()] = mLoopStack.top(); + mLoopStack.pop(); + mCurrentLevel--; return Res; } return RecursiveASTVisitor::TraverseCompoundStmt(S); @@ -144,9 +134,8 @@ class LoopVisitor : public RecursiveASTVisitor { auto Match = mLoopInfo.find(S); if (Match != mLoopInfo.end()) { Loop *MatchLoop = Match->get(); - mForIRs.push_back(MatchLoop); SourceRange Range(S->getBeginLoc(), S->getEndLoc()); - mForLocations.push_back(Range); + mLoopStack.top().push_back(std::make_pair(MatchLoop, Range)); } mState = TraverseState::INNERFOR; auto Res = RecursiveASTVisitor::TraverseForStmt(S); @@ -156,32 +145,42 @@ class LoopVisitor : public RecursiveASTVisitor { return RecursiveASTVisitor::TraverseForStmt(S); } - RangePairVector getRangePairs() const { - return mRangePairs; + const DenseMap &getPragmaLoopsInfo() const { + return mPragmaLoopsInfo; } - LoopPairVector getLoopPairs() const { - return mLoopPairs; + const std::vector> &getPragmaLevels() const { + return mPragmaLevels; } - size_t getLoopCount() const { - return mRangePairs.size(); + size_t getMaxPragmaDepth() const { + return mPragmaLevels.size(); } void printLocations() const { - LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: 'for' loop locations:\n"); - size_t LoopNumber = 0; - for (auto locs: mRangePairs) { - for (auto location : locs) { - LLVM_DEBUG(dbgs() << "Loop #" << LoopNumber << ":\n"); - SourceLocation Begin = location.getBegin(); - SourceLocation End = location.getEnd(); - LLVM_DEBUG(dbgs() << "\tBegin: "); - Begin.print(dbgs(), mSrcMgr); - LLVM_DEBUG(dbgs() << "\n\tEnd: "); - End.print(dbgs(), mSrcMgr); - LLVM_DEBUG(dbgs() << '\n'); - LoopNumber++; + for (size_t Level = 0; Level < mPragmaLevels.size(); Level++) { + LLVM_DEBUG(dbgs() << "Level " << Level << " :\n"); + const auto &CurrentLevel = mPragmaLevels[Level]; + for (size_t PragmaN = 0; PragmaN < CurrentLevel.size(); PragmaN++) { + const auto &Pragma = CurrentLevel[PragmaN]; + auto PragmaItr = mPragmaLoopsInfo.find(Pragma); + assert(PragmaItr != mPragmaLoopsInfo.end() && + "Map should contain all pragmas (as keys) from level vectors."); + const auto &Loops = PragmaItr->second; + LLVM_DEBUG(dbgs() << "\tPragma " << PragmaN << " (" << Pragma <<"):\n"); + for (const auto &Info : Loops) { + const auto LoopPtr = Info.first; + const auto &Range = Info.second; + SourceLocation Begin = Range.getBegin(); + SourceLocation End = Range.getEnd(); + LLVM_DEBUG(dbgs() << "\t\t[Range]\n"); + LLVM_DEBUG(dbgs() << "\t\tBegin:" << Begin.printToString(mSrcMgr) + << "\n"); + LLVM_DEBUG(dbgs() << "\t\tEnd:" << End.printToString(mSrcMgr) <<"\n"); + LLVM_DEBUG(dbgs() << "\t\t\n\t\t[Loop]\n"); + const auto &LoopText = mRewriter.getRewrittenText(Range); + LLVM_DEBUG(dbgs() << "\t\t" << LoopText << "\n\n"); + } } } } @@ -194,10 +193,11 @@ class LoopVisitor : public RecursiveASTVisitor { const LoopMatcherPass::LoopMatcher &mLoopInfo; TraverseState mState; SmallVector mClauses; - RangeVector mForLocations; - LoopVector mForIRs; - RangePairVector mRangePairs; - LoopPairVector mLoopPairs; + + int mCurrentLevel; + std::stack mLoopStack; + std::vector> mPragmaLevels; + DenseMap mPragmaLoopsInfo; }; class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { @@ -213,11 +213,12 @@ class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { private: void swapLoops(const LoopVisitor &Visitor); DIAliasTraitVector getLoopTraits(MDNode *LoopID) const; - bool isSwappingAvailable(const LoopVector &Loops) const; + bool isSwappingAvailable(std::pair &Loops) const; bool hasSameReductionKind(const DIAliasTraitVector &TV0, const DIAliasTraitVector &TV1) const; bool hasTrueOrAntiDependence(const DIAliasTraitVector &TV0, const DIAliasTraitVector &TV1) const; + void removePragmas(const std::vector> &PragmaLevels); Function *mFunction = nullptr; TransformationContext *mTfmCtx = nullptr; @@ -323,17 +324,18 @@ bool ClangLoopSwapping::hasTrueOrAntiDependence( return false; } -bool ClangLoopSwapping::isSwappingAvailable(const LoopVector &Loops) const { +bool ClangLoopSwapping::isSwappingAvailable( + std::pair &Loops) const { auto HasLoopID = [this](MDNode*& LoopID, int LoopN) { if (!LoopID || !(LoopID = mGetLoopID(LoopID))) { LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: ignore loop without ID (loop " << - LoopN << ")."); + LoopN << ").\n"); return false; } return true; }; - auto *LoopID0 = Loops[0]->getLoopID(); - auto *LoopID1 = Loops[1]->getLoopID(); + auto *LoopID0 = Loops.first->getLoopID(); + auto *LoopID1 = Loops.second->getLoopID(); if (!HasLoopID(LoopID0, 0)) return false; if (!HasLoopID(LoopID1, 1)) @@ -353,28 +355,49 @@ bool ClangLoopSwapping::isSwappingAvailable(const LoopVector &Loops) const { } void ClangLoopSwapping::swapLoops(const LoopVisitor &Visitor) { - const auto &RangePairs = Visitor.getRangePairs(); - const auto &LoopPairs = Visitor.getLoopPairs(); - Rewriter &mRewriter = mTfmCtx->getRewriter(); - for (size_t i = 0; i < RangePairs.size(); i++) { - const auto &Ranges = RangePairs[i]; - const auto &Loops = LoopPairs[i]; - if (Ranges.size() < 2) { - toDiag(mSrcMgr->getDiagnostics(), - diag::warn_loop_swapping_missing_loop); - continue; - } - if (Ranges.size() > 2) { - toDiag(mSrcMgr->getDiagnostics(), - diag::warn_loop_swapping_redundant_loop); - } - if (isSwappingAvailable(Loops)) { - const auto &FirstRange = Ranges[0]; - const auto &SecondRange = Ranges[1]; - const auto &FirstLoop = mRewriter.getRewrittenText(FirstRange); - const auto &SecondLoop = mRewriter.getRewrittenText(SecondRange); - mRewriter.ReplaceText(FirstRange, SecondLoop); - mRewriter.ReplaceText(SecondRange, FirstLoop); + Rewriter &Rewr = mTfmCtx->getRewriter(); + auto GetLoopEnd = [this, Rewr](const SourceRange &LoopRange)->SourceLocation { + Token SemiTok; + return (!getRawTokenAfter(LoopRange.getEnd(), *mSrcMgr, + Rewr.getLangOpts(), SemiTok) && SemiTok.is(tok::semi)) ? + SemiTok.getLocation() : LoopRange.getEnd(); + }; + auto &PragmaLevels = Visitor.getPragmaLevels(); + auto &PragmaLoopsInfo = Visitor.getPragmaLoopsInfo(); + for (auto it = PragmaLevels.rbegin(); it != PragmaLevels.rend(); it++) { + for (auto &Pragma : *it) { + auto PragmaItr = PragmaLoopsInfo.find(Pragma); + assert(PragmaItr != PragmaLoopsInfo.end() && + "Map should contain all pragmas (as keys) from level vectors."); + const auto &Loops = PragmaItr->second; + if (Loops.size() < 2) { + toDiag(mSrcMgr->getDiagnostics(), + diag::warn_loop_swapping_missing_loop); + continue; + } + if (Loops.size() > 2) { + toDiag(mSrcMgr->getDiagnostics(), + diag::warn_loop_swapping_redundant_loop); + } + auto Info0 = Loops[0]; + auto Info1 = Loops[1]; + auto Loop0 = Info0.first; + auto Loop1 = Info1.first; + auto LoopPair = std::make_pair(Loop0, Loop1); + if (isSwappingAvailable(LoopPair)) { + auto &Range0 = Info0.second; + auto &Range1 = Info1.second; + Range0.setEnd(GetLoopEnd(Range0)); + Range1.setEnd(GetLoopEnd(Range1)); + auto Range0End = Range0.getEnd(); + auto Range1Begin = Range1.getBegin(); + const auto &LoopText0 = Rewr.getRewrittenText(Range0); + const auto &LoopText1 = Rewr.getRewrittenText(Range1); + Rewr.RemoveText(Range0); + Rewr.RemoveText(Range1); + Rewr.InsertTextBefore(Range0End, LoopText1); + Rewr.InsertTextAfter(Range1Begin, LoopText0); + } } } } @@ -413,8 +436,8 @@ bool ClangLoopSwapping::runOnFunction(Function &F) { LoopVisitor Visitor(mTfmCtx->getRewriter(), mLoopInfo, *ImportInfo); mSrcMgr = &mTfmCtx->getRewriter().getSourceMgr(); Visitor.TraverseDecl(FuncDecl); - if (Visitor.getLoopCount() == 0) { - LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: no loop found.\n"); + if (Visitor.getMaxPragmaDepth() == 0) { + LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: no pragma found.\n"); return false; } Visitor.printLocations(); From f6e3de2656bc935e2ebfbb7700664e3769db41ff Mon Sep 17 00:00:00 2001 From: Julia Lapenko Date: Sun, 8 Nov 2020 17:50:17 +0600 Subject: [PATCH 05/10] [TSAR, Transform] Change data structures and handle more cases. --- include/tsar/Support/DiagnosticKinds.td | 3 + lib/Transform/Clang/LoopSwapping.cpp | 205 +++++++++++------------- 2 files changed, 95 insertions(+), 113 deletions(-) mode change 100644 => 100755 lib/Transform/Clang/LoopSwapping.cpp diff --git a/include/tsar/Support/DiagnosticKinds.td b/include/tsar/Support/DiagnosticKinds.td index 5058cac2..856cf2c0 100644 --- a/include/tsar/Support/DiagnosticKinds.td +++ b/include/tsar/Support/DiagnosticKinds.td @@ -184,3 +184,6 @@ def warn_loop_swapping_diff_reduction: Warning<"unable to swap loops due to the def warn_loop_swapping_true_anti_dependence: Warning<"unable to swap loops due to the true or anti dependence">; def warn_loop_swapping_missing_loop: Warning<"not enough loops for swapping">; def warn_loop_swapping_redundant_loop: Warning<"too many loops for swapping, ignore redundant">; +def error_loop_swapping_lost_loop: Error<"cannot match ForStmt with its IR">; +def error_loop_swapping_expect_compound: Error<"expected compound statement after pragma">; +def warn_loop_swapping_no_loop_id: Warning<"cannot find loop ID to perform swapping">; diff --git a/lib/Transform/Clang/LoopSwapping.cpp b/lib/Transform/Clang/LoopSwapping.cpp old mode 100644 new mode 100755 index aaa857cc..dda52201 --- a/lib/Transform/Clang/LoopSwapping.cpp +++ b/lib/Transform/Clang/LoopSwapping.cpp @@ -1,8 +1,8 @@ -//===- LoopSwapping.cpp - Source-level Renaming of Local Objects - *- C++ -*===// +//===- LoopSwapping.cpp - Loop Swapping (Clang) -----------------*- C++ -*-===// // // Traits Static Analyzer (SAPFOR) // -// Copyright 2018 DVM System Group +// Copyright 2020 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. @@ -22,6 +22,7 @@ // //===----------------------------------------------------------------------===// +#include "tsar/ADT/SpanningTreeRelation.h" #include "tsar/Analysis/AnalysisServer.h" #include "tsar/Analysis/Clang/LoopMatcher.h" #include "tsar/Analysis/Clang/NoMacroAssert.h" @@ -58,7 +59,8 @@ using ClangLoopSwappingProvider = FunctionPassAAProvider; using DIAliasTraitVector = std::vector; using LoopRangeInfo = std::pair; -using LoopRangeVector = SmallVector; +using LoopRangeList = SmallVector; +using PragmaInfoList = SmallVector, 2>; class LoopVisitor : public RecursiveASTVisitor { private: @@ -100,29 +102,29 @@ class LoopVisitor : public RecursiveASTVisitor { /// 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); + /*for (auto SR : ToRemove) + mRewriter.RemoveText(SR, RemoveEmptyLine);*/ mCurrentLevel++; - if (mCurrentLevel + 1 > int(mPragmaLevels.size())) { - mPragmaLevels.resize(mCurrentLevel + 1); - } - mPragmaLevels[mCurrentLevel].push_back(S); + mPragmaLoopsInfo.resize(mPragmaLoopsInfo.size() + 1); + mPragmaLoopsInfo.back().first = S; mState = TraverseState::PRAGMA; } return true; } - auto Res = RecursiveASTVisitor::TraverseStmt(S); - return Res; + if (mState == TraverseState::PRAGMA && !dyn_cast(S)) { + S->dump(); + toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), + diag::error_loop_swapping_expect_compound); + return false; + } + return RecursiveASTVisitor::TraverseStmt(S); } bool TraverseCompoundStmt(CompoundStmt *S) { if (mState == TraverseState::PRAGMA) { mState = TraverseState::OUTERFOR; - mLoopStack.push(LoopRangeVector()); auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S); - mState = TraverseState::PRAGMA; - mPragmaLoopsInfo[mPragmaLevels[mCurrentLevel].back()] = mLoopStack.top(); - mLoopStack.pop(); + mState = TraverseState::NONE; mCurrentLevel--; return Res; } @@ -133,9 +135,11 @@ class LoopVisitor : public RecursiveASTVisitor { if (mState == TraverseState::OUTERFOR) { auto Match = mLoopInfo.find(S); if (Match != mLoopInfo.end()) { - Loop *MatchLoop = Match->get(); - SourceRange Range(S->getBeginLoc(), S->getEndLoc()); - mLoopStack.top().push_back(std::make_pair(MatchLoop, Range)); + mPragmaLoopsInfo.back().second.push_back( + std::make_pair(Match->get(), S->getSourceRange())); + } else { + toDiag(mSrcMgr.getDiagnostics(), S->getBeginLoc(), + diag::error_loop_swapping_lost_loop); } mState = TraverseState::INNERFOR; auto Res = RecursiveASTVisitor::TraverseForStmt(S); @@ -145,45 +149,34 @@ class LoopVisitor : public RecursiveASTVisitor { return RecursiveASTVisitor::TraverseForStmt(S); } - const DenseMap &getPragmaLoopsInfo() const { + const PragmaInfoList &getPragmaLoopsInfo() const { return mPragmaLoopsInfo; } - const std::vector> &getPragmaLevels() const { - return mPragmaLevels; - } - - size_t getMaxPragmaDepth() const { - return mPragmaLevels.size(); + bool hasPragma() const { + return !mPragmaLoopsInfo.empty(); } + #ifdef LLVM_DEBUG void printLocations() const { - for (size_t Level = 0; Level < mPragmaLevels.size(); Level++) { - LLVM_DEBUG(dbgs() << "Level " << Level << " :\n"); - const auto &CurrentLevel = mPragmaLevels[Level]; - for (size_t PragmaN = 0; PragmaN < CurrentLevel.size(); PragmaN++) { - const auto &Pragma = CurrentLevel[PragmaN]; - auto PragmaItr = mPragmaLoopsInfo.find(Pragma); - assert(PragmaItr != mPragmaLoopsInfo.end() && - "Map should contain all pragmas (as keys) from level vectors."); - const auto &Loops = PragmaItr->second; - LLVM_DEBUG(dbgs() << "\tPragma " << PragmaN << " (" << Pragma <<"):\n"); - for (const auto &Info : Loops) { - const auto LoopPtr = Info.first; - const auto &Range = Info.second; - SourceLocation Begin = Range.getBegin(); - SourceLocation End = Range.getEnd(); - LLVM_DEBUG(dbgs() << "\t\t[Range]\n"); - LLVM_DEBUG(dbgs() << "\t\tBegin:" << Begin.printToString(mSrcMgr) - << "\n"); - LLVM_DEBUG(dbgs() << "\t\tEnd:" << End.printToString(mSrcMgr) <<"\n"); - LLVM_DEBUG(dbgs() << "\t\t\n\t\t[Loop]\n"); - const auto &LoopText = mRewriter.getRewrittenText(Range); - LLVM_DEBUG(dbgs() << "\t\t" << LoopText << "\n\n"); - } + int N = 0; + for (auto It = mPragmaLoopsInfo.begin(); It != mPragmaLoopsInfo.end(); + ++It, ++N) { + dbgs() << "\tPragma " << N << " (" << It->first <<"):\n"; + for (const auto &Info : It->second) { + const auto LoopPtr = Info.first; + const auto &Range = Info.second; + dbgs() << "\t\t[Range]\n"; + dbgs() << "\t\tBegin:" << Range.getBegin().printToString(mSrcMgr) + << "\n"; + dbgs() << "\t\tEnd:" << Range.getEnd().printToString(mSrcMgr) <<"\n"; + dbgs() << "\t\t\n\t\t[Loop]\n"; + const auto &LoopText = mRewriter.getRewrittenText(Range); + dbgs() << "\t\t" << LoopText << "\n\n"; } } } + #endif private: Rewriter &mRewriter; @@ -195,9 +188,7 @@ class LoopVisitor : public RecursiveASTVisitor { SmallVector mClauses; int mCurrentLevel; - std::stack mLoopStack; - std::vector> mPragmaLevels; - DenseMap mPragmaLoopsInfo; + PragmaInfoList mPragmaLoopsInfo; }; class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { @@ -213,12 +204,11 @@ class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { private: void swapLoops(const LoopVisitor &Visitor); DIAliasTraitVector getLoopTraits(MDNode *LoopID) const; - bool isSwappingAvailable(std::pair &Loops) const; + bool isSwappingAvailable(const LoopRangeList &LRL, const Stmt *Pragma) const; bool hasSameReductionKind(const DIAliasTraitVector &TV0, const DIAliasTraitVector &TV1) const; bool hasTrueOrAntiDependence(const DIAliasTraitVector &TV0, const DIAliasTraitVector &TV1) const; - void removePragmas(const std::vector> &PragmaLevels); Function *mFunction = nullptr; TransformationContext *mTfmCtx = nullptr; @@ -304,17 +294,15 @@ bool ClangLoopSwapping::hasSameReductionKind( bool ClangLoopSwapping::hasTrueOrAntiDependence( const DIAliasTraitVector &TV0, const DIAliasTraitVector &TV1) const { + SpanningTreeRelation STR(mDIAT); for (auto &TS0: TV0) { - auto *Node0 = TS0->getNode(); - MemoryDescriptor Dptr0 = *TS0; for (auto &TS1: TV1) { - auto *Node1 = TS1->getNode(); - MemoryDescriptor Dptr1 = *TS1; - if (Node0 == Node1) { - if (Dptr0.is() && !Dptr1.is()) { + if (!STR.isUnreachable(const_cast(TS0->getNode()), + const_cast(TS1->getNode()))) { + if (TS0->is() && !TS1->is()) { // anti dependence return true; - } else if (Dptr1.is() && !Dptr0.is()){ + } else if (TS1->is() && !TS0->is()){ // true dependence return true; } @@ -325,29 +313,28 @@ bool ClangLoopSwapping::hasTrueOrAntiDependence( } bool ClangLoopSwapping::isSwappingAvailable( - std::pair &Loops) const { - auto HasLoopID = [this](MDNode*& LoopID, int LoopN) { - if (!LoopID || !(LoopID = mGetLoopID(LoopID))) { - LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: ignore loop without ID (loop " << - LoopN << ").\n"); - return false; - } - return true; - }; - auto *LoopID0 = Loops.first->getLoopID(); - auto *LoopID1 = Loops.second->getLoopID(); - if (!HasLoopID(LoopID0, 0)) + const LoopRangeList &LRL, const Stmt *Pragma) const { + auto *LoopID0 = mGetLoopID(LRL[0].first->getLoopID()); + auto *LoopID1 = mGetLoopID(LRL[1].first->getLoopID()); + if (!LoopID0) { + toDiag(mSrcMgr->getDiagnostics(), LRL[0].second.getBegin(), + diag::warn_loop_swapping_no_loop_id); return false; - if (!HasLoopID(LoopID1, 1)) + } + if (!LoopID1) { + toDiag(mSrcMgr->getDiagnostics(), LRL[1].second.getBegin(), + diag::warn_loop_swapping_no_loop_id); return false; + } auto Traits0 = getLoopTraits(LoopID0); auto Traits1 = getLoopTraits(LoopID1); if (!hasSameReductionKind(Traits0, Traits1)) { - toDiag(mSrcMgr->getDiagnostics(), diag::warn_loop_swapping_diff_reduction); + toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), + diag::warn_loop_swapping_diff_reduction); return false; } if (hasTrueOrAntiDependence(Traits0, Traits1)) { - toDiag(mSrcMgr->getDiagnostics(), + toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), diag::warn_loop_swapping_true_anti_dependence); return false; } @@ -356,48 +343,38 @@ bool ClangLoopSwapping::isSwappingAvailable( void ClangLoopSwapping::swapLoops(const LoopVisitor &Visitor) { Rewriter &Rewr = mTfmCtx->getRewriter(); - auto GetLoopEnd = [this, Rewr](const SourceRange &LoopRange)->SourceLocation { + auto GetLoopEnd = [this, &Rewr](const SourceRange &LoopRange) { Token SemiTok; return (!getRawTokenAfter(LoopRange.getEnd(), *mSrcMgr, Rewr.getLangOpts(), SemiTok) && SemiTok.is(tok::semi)) ? SemiTok.getLocation() : LoopRange.getEnd(); }; - auto &PragmaLevels = Visitor.getPragmaLevels(); auto &PragmaLoopsInfo = Visitor.getPragmaLoopsInfo(); - for (auto it = PragmaLevels.rbegin(); it != PragmaLevels.rend(); it++) { - for (auto &Pragma : *it) { - auto PragmaItr = PragmaLoopsInfo.find(Pragma); - assert(PragmaItr != PragmaLoopsInfo.end() && - "Map should contain all pragmas (as keys) from level vectors."); - const auto &Loops = PragmaItr->second; - if (Loops.size() < 2) { - toDiag(mSrcMgr->getDiagnostics(), - diag::warn_loop_swapping_missing_loop); - continue; - } - if (Loops.size() > 2) { - toDiag(mSrcMgr->getDiagnostics(), - diag::warn_loop_swapping_redundant_loop); - } - auto Info0 = Loops[0]; - auto Info1 = Loops[1]; - auto Loop0 = Info0.first; - auto Loop1 = Info1.first; - auto LoopPair = std::make_pair(Loop0, Loop1); - if (isSwappingAvailable(LoopPair)) { - auto &Range0 = Info0.second; - auto &Range1 = Info1.second; - Range0.setEnd(GetLoopEnd(Range0)); - Range1.setEnd(GetLoopEnd(Range1)); - auto Range0End = Range0.getEnd(); - auto Range1Begin = Range1.getBegin(); - const auto &LoopText0 = Rewr.getRewrittenText(Range0); - const auto &LoopText1 = Rewr.getRewrittenText(Range1); - Rewr.RemoveText(Range0); - Rewr.RemoveText(Range1); - Rewr.InsertTextBefore(Range0End, LoopText1); - Rewr.InsertTextAfter(Range1Begin, LoopText0); - } + for (auto It = PragmaLoopsInfo.begin(); It != PragmaLoopsInfo.end(); It++) { + auto &Pragma = It->first; + auto &Loops = It->second; + if (Loops.size() < 2) { + toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), + diag::warn_loop_swapping_missing_loop); + continue; + } + if (Loops.size() > 2) { + toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), + diag::warn_loop_swapping_redundant_loop); + } + if (isSwappingAvailable(Loops, Pragma)) { + auto Range0 = Loops[0].second; + auto Range1 = Loops[1].second; + Range0.setEnd(GetLoopEnd(Range0)); + Range1.setEnd(GetLoopEnd(Range1)); + auto Range0End = Range0.getEnd(); + auto Range1Begin = Range1.getBegin(); + const auto &LoopText0 = Rewr.getRewrittenText(Range0); + const auto &LoopText1 = Rewr.getRewrittenText(Range1); + Rewr.RemoveText(Range0); + Rewr.RemoveText(Range1); + Rewr.InsertTextBefore(Range0End, LoopText1); + Rewr.InsertTextAfter(Range1Begin, LoopText0); } } } @@ -436,11 +413,13 @@ bool ClangLoopSwapping::runOnFunction(Function &F) { LoopVisitor Visitor(mTfmCtx->getRewriter(), mLoopInfo, *ImportInfo); mSrcMgr = &mTfmCtx->getRewriter().getSourceMgr(); Visitor.TraverseDecl(FuncDecl); - if (Visitor.getMaxPragmaDepth() == 0) { + if (mSrcMgr->getDiagnostics().hasErrorOccurred()) + return false; + if (!Visitor.hasPragma()) { LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: no pragma found.\n"); return false; } - Visitor.printLocations(); + LLVM_DEBUG(Visitor.printLocations()); swapLoops(Visitor); return false; } From 24088637be651d835ee5425cfc857eabeb862831 Mon Sep 17 00:00:00 2001 From: Julia Lapenko Date: Sun, 8 Nov 2020 23:08:46 +0600 Subject: [PATCH 06/10] [TSAR, Transform] Limit scopes of loops for swapping. --- include/tsar/Support/DiagnosticKinds.td | 4 ++- lib/Transform/Clang/LoopSwapping.cpp | 47 ++++++++++++++++--------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/include/tsar/Support/DiagnosticKinds.td b/include/tsar/Support/DiagnosticKinds.td index 856cf2c0..763133ef 100644 --- a/include/tsar/Support/DiagnosticKinds.td +++ b/include/tsar/Support/DiagnosticKinds.td @@ -184,6 +184,8 @@ def warn_loop_swapping_diff_reduction: Warning<"unable to swap loops due to the def warn_loop_swapping_true_anti_dependence: Warning<"unable to swap loops due to the true or anti dependence">; def warn_loop_swapping_missing_loop: Warning<"not enough loops for swapping">; def warn_loop_swapping_redundant_loop: Warning<"too many loops for swapping, ignore redundant">; +def warn_loop_swapping_no_loop_id: Warning<"cannot find loop ID to perform swapping">; + def error_loop_swapping_lost_loop: Error<"cannot match ForStmt with its IR">; def error_loop_swapping_expect_compound: Error<"expected compound statement after pragma">; -def warn_loop_swapping_no_loop_id: Warning<"cannot find loop ID to perform swapping">; +def error_loop_swapping_diff_scope: Error<"loops within a pragma must have the same scope">; diff --git a/lib/Transform/Clang/LoopSwapping.cpp b/lib/Transform/Clang/LoopSwapping.cpp index dda52201..54102cb5 100755 --- a/lib/Transform/Clang/LoopSwapping.cpp +++ b/lib/Transform/Clang/LoopSwapping.cpp @@ -54,11 +54,19 @@ using namespace tsar; namespace { +struct LoopRangeInfo { + Loop *LoopPtr; + SourceRange Range; + CompoundStmt *CompStmtPtr; + LoopRangeInfo() : LoopPtr(nullptr), CompStmtPtr(nullptr) {} + LoopRangeInfo(llvm::Loop *L, const SourceRange &R, CompoundStmt *S): + LoopPtr(L), Range(R), CompStmtPtr(S) {} +}; + /// This provides access to function-level analysis results on server. using ClangLoopSwappingProvider = FunctionPassAAProvider; using DIAliasTraitVector = std::vector; -using LoopRangeInfo = std::pair; using LoopRangeList = SmallVector; using PragmaInfoList = SmallVector, 2>; @@ -74,7 +82,6 @@ class LoopVisitor : public RecursiveASTVisitor { , mLangOpts(Rewr.getLangOpts()) , mLoopInfo(LM) , mState(TraverseState::NONE) - , mCurrentLevel(-1) {} bool TraverseStmt(Stmt *S) { @@ -104,7 +111,6 @@ class LoopVisitor : public RecursiveASTVisitor { RemoveEmptyLine.RemoveLineIfEmpty = false; /*for (auto SR : ToRemove) mRewriter.RemoveText(SR, RemoveEmptyLine);*/ - mCurrentLevel++; mPragmaLoopsInfo.resize(mPragmaLoopsInfo.size() + 1); mPragmaLoopsInfo.back().first = S; mState = TraverseState::PRAGMA; @@ -121,22 +127,30 @@ class LoopVisitor : public RecursiveASTVisitor { } bool TraverseCompoundStmt(CompoundStmt *S) { + mCompStmtStack.push(S); if (mState == TraverseState::PRAGMA) { mState = TraverseState::OUTERFOR; auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S); mState = TraverseState::NONE; - mCurrentLevel--; return Res; } - return RecursiveASTVisitor::TraverseCompoundStmt(S); + auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S); + mCompStmtStack.pop(); + return Res; } bool TraverseForStmt(ForStmt *S) { if (mState == TraverseState::OUTERFOR) { auto Match = mLoopInfo.find(S); if (Match != mLoopInfo.end()) { - mPragmaLoopsInfo.back().second.push_back( - std::make_pair(Match->get(), S->getSourceRange())); + auto &LRL = mPragmaLoopsInfo.back().second; + if (!LRL.empty() && LRL.back().CompStmtPtr != mCompStmtStack.top()) { + toDiag(mSrcMgr.getDiagnostics(), S->getBeginLoc(), + diag::error_loop_swapping_diff_scope); + return false; + } + LRL.push_back(LoopRangeInfo(Match->get(), S->getSourceRange(), + mCompStmtStack.top())); } else { toDiag(mSrcMgr.getDiagnostics(), S->getBeginLoc(), diag::error_loop_swapping_lost_loop); @@ -164,8 +178,8 @@ class LoopVisitor : public RecursiveASTVisitor { ++It, ++N) { dbgs() << "\tPragma " << N << " (" << It->first <<"):\n"; for (const auto &Info : It->second) { - const auto LoopPtr = Info.first; - const auto &Range = Info.second; + const auto LoopPtr = Info.LoopPtr; + const auto &Range = Info.Range; dbgs() << "\t\t[Range]\n"; dbgs() << "\t\tBegin:" << Range.getBegin().printToString(mSrcMgr) << "\n"; @@ -186,8 +200,7 @@ class LoopVisitor : public RecursiveASTVisitor { const LoopMatcherPass::LoopMatcher &mLoopInfo; TraverseState mState; SmallVector mClauses; - - int mCurrentLevel; + std::stack mCompStmtStack; PragmaInfoList mPragmaLoopsInfo; }; @@ -314,15 +327,15 @@ bool ClangLoopSwapping::hasTrueOrAntiDependence( bool ClangLoopSwapping::isSwappingAvailable( const LoopRangeList &LRL, const Stmt *Pragma) const { - auto *LoopID0 = mGetLoopID(LRL[0].first->getLoopID()); - auto *LoopID1 = mGetLoopID(LRL[1].first->getLoopID()); + auto *LoopID0 = mGetLoopID(LRL[0].LoopPtr->getLoopID()); + auto *LoopID1 = mGetLoopID(LRL[1].LoopPtr->getLoopID()); if (!LoopID0) { - toDiag(mSrcMgr->getDiagnostics(), LRL[0].second.getBegin(), + toDiag(mSrcMgr->getDiagnostics(), LRL[0].Range.getBegin(), diag::warn_loop_swapping_no_loop_id); return false; } if (!LoopID1) { - toDiag(mSrcMgr->getDiagnostics(), LRL[1].second.getBegin(), + toDiag(mSrcMgr->getDiagnostics(), LRL[1].Range.getBegin(), diag::warn_loop_swapping_no_loop_id); return false; } @@ -363,8 +376,8 @@ void ClangLoopSwapping::swapLoops(const LoopVisitor &Visitor) { diag::warn_loop_swapping_redundant_loop); } if (isSwappingAvailable(Loops, Pragma)) { - auto Range0 = Loops[0].second; - auto Range1 = Loops[1].second; + auto Range0 = Loops[0].Range; + auto Range1 = Loops[1].Range; Range0.setEnd(GetLoopEnd(Range0)); Range1.setEnd(GetLoopEnd(Range1)); auto Range0End = Range0.getEnd(); From dc4fead9f19eeeee6785cf3fa6f95c298c33478e Mon Sep 17 00:00:00 2001 From: Julia Lapenko Date: Mon, 9 Nov 2020 00:02:43 +0600 Subject: [PATCH 07/10] [TSAR, Transform] Limit statements in pragma --- include/tsar/Support/DiagnosticKinds.td | 2 +- lib/Transform/Clang/LoopSwapping.cpp | 42 +++++++++---------------- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/include/tsar/Support/DiagnosticKinds.td b/include/tsar/Support/DiagnosticKinds.td index 763133ef..8792cf82 100644 --- a/include/tsar/Support/DiagnosticKinds.td +++ b/include/tsar/Support/DiagnosticKinds.td @@ -188,4 +188,4 @@ def warn_loop_swapping_no_loop_id: Warning<"cannot find loop ID to perform swapp def error_loop_swapping_lost_loop: Error<"cannot match ForStmt with its IR">; def error_loop_swapping_expect_compound: Error<"expected compound statement after pragma">; -def error_loop_swapping_diff_scope: Error<"loops within a pragma must have the same scope">; +def error_loop_swapping_redundant_stmt: Error<"pragma should only contain loops or other pragma">; diff --git a/lib/Transform/Clang/LoopSwapping.cpp b/lib/Transform/Clang/LoopSwapping.cpp index 54102cb5..0704af1c 100755 --- a/lib/Transform/Clang/LoopSwapping.cpp +++ b/lib/Transform/Clang/LoopSwapping.cpp @@ -54,19 +54,11 @@ using namespace tsar; namespace { -struct LoopRangeInfo { - Loop *LoopPtr; - SourceRange Range; - CompoundStmt *CompStmtPtr; - LoopRangeInfo() : LoopPtr(nullptr), CompStmtPtr(nullptr) {} - LoopRangeInfo(llvm::Loop *L, const SourceRange &R, CompoundStmt *S): - LoopPtr(L), Range(R), CompStmtPtr(S) {} -}; - /// This provides access to function-level analysis results on server. using ClangLoopSwappingProvider = FunctionPassAAProvider; using DIAliasTraitVector = std::vector; +using LoopRangeInfo = std::pair; using LoopRangeList = SmallVector; using PragmaInfoList = SmallVector, 2>; @@ -123,11 +115,15 @@ class LoopVisitor : public RecursiveASTVisitor { diag::error_loop_swapping_expect_compound); return false; } + if (mState == TraverseState::OUTERFOR && !dyn_cast(S)) { + toDiag(mSrcMgr.getDiagnostics(), S->getBeginLoc(), + diag::error_loop_swapping_redundant_stmt); + return false; + } return RecursiveASTVisitor::TraverseStmt(S); } bool TraverseCompoundStmt(CompoundStmt *S) { - mCompStmtStack.push(S); if (mState == TraverseState::PRAGMA) { mState = TraverseState::OUTERFOR; auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S); @@ -135,7 +131,6 @@ class LoopVisitor : public RecursiveASTVisitor { return Res; } auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S); - mCompStmtStack.pop(); return Res; } @@ -144,13 +139,7 @@ class LoopVisitor : public RecursiveASTVisitor { auto Match = mLoopInfo.find(S); if (Match != mLoopInfo.end()) { auto &LRL = mPragmaLoopsInfo.back().second; - if (!LRL.empty() && LRL.back().CompStmtPtr != mCompStmtStack.top()) { - toDiag(mSrcMgr.getDiagnostics(), S->getBeginLoc(), - diag::error_loop_swapping_diff_scope); - return false; - } - LRL.push_back(LoopRangeInfo(Match->get(), S->getSourceRange(), - mCompStmtStack.top())); + LRL.push_back(std::make_pair(Match->get(), S->getSourceRange())); } else { toDiag(mSrcMgr.getDiagnostics(), S->getBeginLoc(), diag::error_loop_swapping_lost_loop); @@ -178,8 +167,8 @@ class LoopVisitor : public RecursiveASTVisitor { ++It, ++N) { dbgs() << "\tPragma " << N << " (" << It->first <<"):\n"; for (const auto &Info : It->second) { - const auto LoopPtr = Info.LoopPtr; - const auto &Range = Info.Range; + const auto LoopPtr = Info.first; + const auto &Range = Info.second; dbgs() << "\t\t[Range]\n"; dbgs() << "\t\tBegin:" << Range.getBegin().printToString(mSrcMgr) << "\n"; @@ -200,7 +189,6 @@ class LoopVisitor : public RecursiveASTVisitor { const LoopMatcherPass::LoopMatcher &mLoopInfo; TraverseState mState; SmallVector mClauses; - std::stack mCompStmtStack; PragmaInfoList mPragmaLoopsInfo; }; @@ -327,15 +315,15 @@ bool ClangLoopSwapping::hasTrueOrAntiDependence( bool ClangLoopSwapping::isSwappingAvailable( const LoopRangeList &LRL, const Stmt *Pragma) const { - auto *LoopID0 = mGetLoopID(LRL[0].LoopPtr->getLoopID()); - auto *LoopID1 = mGetLoopID(LRL[1].LoopPtr->getLoopID()); + auto *LoopID0 = mGetLoopID(LRL[0].first->getLoopID()); + auto *LoopID1 = mGetLoopID(LRL[1].first->getLoopID()); if (!LoopID0) { - toDiag(mSrcMgr->getDiagnostics(), LRL[0].Range.getBegin(), + toDiag(mSrcMgr->getDiagnostics(), LRL[0].second.getBegin(), diag::warn_loop_swapping_no_loop_id); return false; } if (!LoopID1) { - toDiag(mSrcMgr->getDiagnostics(), LRL[1].Range.getBegin(), + toDiag(mSrcMgr->getDiagnostics(), LRL[1].second.getBegin(), diag::warn_loop_swapping_no_loop_id); return false; } @@ -376,8 +364,8 @@ void ClangLoopSwapping::swapLoops(const LoopVisitor &Visitor) { diag::warn_loop_swapping_redundant_loop); } if (isSwappingAvailable(Loops, Pragma)) { - auto Range0 = Loops[0].Range; - auto Range1 = Loops[1].Range; + auto Range0 = Loops[0].second; + auto Range1 = Loops[1].second; Range0.setEnd(GetLoopEnd(Range0)); Range1.setEnd(GetLoopEnd(Range1)); auto Range0End = Range0.getEnd(); From c03f3eb203e35db42eb05883f139c235de238743 Mon Sep 17 00:00:00 2001 From: Julia Lapenko Date: Sun, 13 Dec 2020 19:15:54 +0600 Subject: [PATCH 08/10] [TSAR, Transform] Change traversal of pragma loops. --- include/tsar/Support/DiagnosticKinds.td | 6 +- lib/Transform/Clang/LoopSwapping.cpp | 81 +++++++++++++------------ 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/include/tsar/Support/DiagnosticKinds.td b/include/tsar/Support/DiagnosticKinds.td index 8792cf82..6c8c2637 100644 --- a/include/tsar/Support/DiagnosticKinds.td +++ b/include/tsar/Support/DiagnosticKinds.td @@ -185,7 +185,7 @@ def warn_loop_swapping_true_anti_dependence: Warning<"unable to swap loops due t def warn_loop_swapping_missing_loop: Warning<"not enough loops for swapping">; def warn_loop_swapping_redundant_loop: Warning<"too many loops for swapping, ignore redundant">; def warn_loop_swapping_no_loop_id: Warning<"cannot find loop ID to perform swapping">; - -def error_loop_swapping_lost_loop: Error<"cannot match ForStmt with its IR">; +def warn_loop_swapping_lost_loop: Warning<"cannot match ForStmt with its IR">; +def warn_loop_swapping_redundant_stmt: Warning<"pragma should only contain loops or other pragma">; def error_loop_swapping_expect_compound: Error<"expected compound statement after pragma">; -def error_loop_swapping_redundant_stmt: Error<"pragma should only contain loops or other pragma">; + diff --git a/lib/Transform/Clang/LoopSwapping.cpp b/lib/Transform/Clang/LoopSwapping.cpp index 0704af1c..4c2c4a4a 100755 --- a/lib/Transform/Clang/LoopSwapping.cpp +++ b/lib/Transform/Clang/LoopSwapping.cpp @@ -29,9 +29,9 @@ #include "tsar/Analysis/Memory/DIDependencyAnalysis.h" #include "tsar/Analysis/Memory/DIEstimateMemory.h" #include "tsar/Analysis/Memory/MemoryTraitUtils.h" -#include "tsar/Core/TransformationContext.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/Clang/Utils.h" #include "tsar/Support/Clang/SourceLocationTraverse.h" @@ -42,7 +42,6 @@ #include #include #include -#include #include using namespace llvm; @@ -57,10 +56,10 @@ namespace { /// This provides access to function-level analysis results on server. using ClangLoopSwappingProvider = FunctionPassAAProvider; -using DIAliasTraitVector = std::vector; +using DIAliasTraitList = SmallVector; using LoopRangeInfo = std::pair; using LoopRangeList = SmallVector; -using PragmaInfoList = SmallVector, 2>; +using PragmaInfoList = DenseMap; class LoopVisitor : public RecursiveASTVisitor { private: @@ -103,8 +102,8 @@ class LoopVisitor : public RecursiveASTVisitor { RemoveEmptyLine.RemoveLineIfEmpty = false; /*for (auto SR : ToRemove) mRewriter.RemoveText(SR, RemoveEmptyLine);*/ - mPragmaLoopsInfo.resize(mPragmaLoopsInfo.size() + 1); - mPragmaLoopsInfo.back().first = S; + mPragmaLoopsInfo.insert(std::make_pair(S, LoopRangeList())); + mPragmaStack.push(S); mState = TraverseState::PRAGMA; } return true; @@ -117,7 +116,7 @@ class LoopVisitor : public RecursiveASTVisitor { } if (mState == TraverseState::OUTERFOR && !dyn_cast(S)) { toDiag(mSrcMgr.getDiagnostics(), S->getBeginLoc(), - diag::error_loop_swapping_redundant_stmt); + diag::warn_loop_swapping_redundant_stmt); return false; } return RecursiveASTVisitor::TraverseStmt(S); @@ -127,22 +126,22 @@ class LoopVisitor : public RecursiveASTVisitor { if (mState == TraverseState::PRAGMA) { mState = TraverseState::OUTERFOR; auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S); - mState = TraverseState::NONE; + mPragmaStack.pop(); + mState = mPragmaStack.empty() ? TraverseState::NONE : TraverseState::OUTERFOR; return Res; } - auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S); - return Res; + return RecursiveASTVisitor::TraverseCompoundStmt(S); } bool TraverseForStmt(ForStmt *S) { if (mState == TraverseState::OUTERFOR) { auto Match = mLoopInfo.find(S); if (Match != mLoopInfo.end()) { - auto &LRL = mPragmaLoopsInfo.back().second; + auto &LRL = mPragmaLoopsInfo[mPragmaStack.top()]; LRL.push_back(std::make_pair(Match->get(), S->getSourceRange())); } else { toDiag(mSrcMgr.getDiagnostics(), S->getBeginLoc(), - diag::error_loop_swapping_lost_loop); + diag::warn_loop_swapping_lost_loop); } mState = TraverseState::INNERFOR; auto Res = RecursiveASTVisitor::TraverseForStmt(S); @@ -165,17 +164,17 @@ class LoopVisitor : public RecursiveASTVisitor { int N = 0; for (auto It = mPragmaLoopsInfo.begin(); It != mPragmaLoopsInfo.end(); ++It, ++N) { - dbgs() << "\tPragma " << N << " (" << It->first <<"):\n"; + dbgs() << "Pragma " << N << " (" << It->first <<"):\n"; for (const auto &Info : It->second) { const auto LoopPtr = Info.first; const auto &Range = Info.second; - dbgs() << "\t\t[Range]\n"; - dbgs() << "\t\tBegin:" << Range.getBegin().printToString(mSrcMgr) + dbgs() << "\t[Range]\n"; + dbgs() << "\tBegin:" << Range.getBegin().printToString(mSrcMgr) << "\n"; - dbgs() << "\t\tEnd:" << Range.getEnd().printToString(mSrcMgr) <<"\n"; - dbgs() << "\t\t\n\t\t[Loop]\n"; + dbgs() << "\tEnd:" << Range.getEnd().printToString(mSrcMgr) <<"\n"; + dbgs() << "\t\n\t\t[Loop]\n"; const auto &LoopText = mRewriter.getRewrittenText(Range); - dbgs() << "\t\t" << LoopText << "\n\n"; + dbgs() << "\t" << LoopText << "\n\n"; } } } @@ -189,7 +188,8 @@ class LoopVisitor : public RecursiveASTVisitor { const LoopMatcherPass::LoopMatcher &mLoopInfo; TraverseState mState; SmallVector mClauses; - PragmaInfoList mPragmaLoopsInfo; + PragmaInfoList mPragmaLoopsInfo; + std::stack mPragmaStack; }; class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { @@ -204,12 +204,12 @@ class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { private: void swapLoops(const LoopVisitor &Visitor); - DIAliasTraitVector getLoopTraits(MDNode *LoopID) const; + DIAliasTraitList getLoopTraits(MDNode *LoopID) const; bool isSwappingAvailable(const LoopRangeList &LRL, const Stmt *Pragma) const; - bool hasSameReductionKind(const DIAliasTraitVector &TV0, - const DIAliasTraitVector &TV1) const; - bool hasTrueOrAntiDependence(const DIAliasTraitVector &TV0, - const DIAliasTraitVector &TV1) const; + bool hasSameReductionKind(const DIAliasTraitList &TV0, + const DIAliasTraitList &TV1) const; + bool hasTrueOrAntiDependence(const DIAliasTraitList &TV0, + const DIAliasTraitList &TV1) const; Function *mFunction = nullptr; TransformationContext *mTfmCtx = nullptr; @@ -244,14 +244,14 @@ class ClangLoopSwappingInfo final : public PassGroupInfo { char ClangLoopSwapping::ID = 0; -DIAliasTraitVector ClangLoopSwapping::getLoopTraits(MDNode *LoopID) const { +DIAliasTraitList ClangLoopSwapping::getLoopTraits(MDNode *LoopID) const { auto DepItr = mDIDepInfo->find(LoopID); assert(DepItr != mDIDepInfo->end() && "Loop must be analyzed!"); auto &DIDepSet = DepItr->get(); DenseSet Coverage; accessCoverage(DIDepSet, *mDIAT, Coverage, mGlobalOpts->IgnoreRedundantMemory); - DIAliasTraitVector Traits; + DIAliasTraitList Traits; for (auto &TS : DIDepSet) { if (!Coverage.count(TS.getNode())) continue; @@ -261,20 +261,17 @@ DIAliasTraitVector ClangLoopSwapping::getLoopTraits(MDNode *LoopID) const { } bool ClangLoopSwapping::hasSameReductionKind( - const DIAliasTraitVector &TV0, const DIAliasTraitVector &TV1) const { + const DIAliasTraitList &TV0, const DIAliasTraitList &TV1) const { for (auto &TS0: TV0) { - auto *Node0 = TS0->getNode(); - MemoryDescriptor Dptr0 = *TS0; - if (!Dptr0.is()) + if (!TS0->is()) continue; + auto *Node0 = TS0->getNode(); for (auto &TS1: TV1) { auto *Node1 = TS1->getNode(); - MemoryDescriptor Dptr1 = *TS1; - if (Node0 == Node1 && Dptr1.is()) { + if (Node0 == Node1 && TS1->is()) { LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: Same nodes with reduction.\n"); - auto I0 = TS0->begin(), I1 = TS1->begin(); - auto *Red0 = (**I0).get(); - auto *Red1 = (**I1).get(); + auto *Red0 = (**TS0->begin()).get(); + auto *Red1 = (**TS1->begin()).get(); if (!Red0 || !Red1) { LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: Unknown Reduction.\n"); return false; @@ -294,7 +291,7 @@ bool ClangLoopSwapping::hasSameReductionKind( } bool ClangLoopSwapping::hasTrueOrAntiDependence( - const DIAliasTraitVector &TV0, const DIAliasTraitVector &TV1) const { + const DIAliasTraitList &TV0, const DIAliasTraitList &TV1) const { SpanningTreeRelation STR(mDIAT); for (auto &TS0: TV0) { for (auto &TS1: TV1) { @@ -315,8 +312,11 @@ bool ClangLoopSwapping::hasTrueOrAntiDependence( bool ClangLoopSwapping::isSwappingAvailable( const LoopRangeList &LRL, const Stmt *Pragma) const { - auto *LoopID0 = mGetLoopID(LRL[0].first->getLoopID()); - auto *LoopID1 = mGetLoopID(LRL[1].first->getLoopID()); + auto ClientLoopID0 = LRL[0].first->getLoopID(); + auto ClientLoopID1 = LRL[1].first->getLoopID(); + assert(ClientLoopID0 && ClientLoopID1 && "LoopID must not be null!"); + auto *LoopID0 = mGetLoopID(ClientLoopID0); + auto *LoopID1 = mGetLoopID(ClientLoopID1); if (!LoopID0) { toDiag(mSrcMgr->getDiagnostics(), LRL[0].second.getBegin(), diag::warn_loop_swapping_no_loop_id); @@ -383,10 +383,11 @@ void ClangLoopSwapping::swapLoops(const LoopVisitor &Visitor) { bool ClangLoopSwapping::runOnFunction(Function &F) { mFunction = &F; auto *M = F.getParent(); - mTfmCtx = getAnalysis().getContext(*M); + auto &TfmInfo = getAnalysis(); + mTfmCtx = TfmInfo ? TfmInfo->getContext(*M) : nullptr; if (!mTfmCtx || !mTfmCtx->hasInstance()) { M->getContext().emitError("can not transform sources" - ": transformation context is not available"); + ": transformation context is not available"); return false; } auto FuncDecl = mTfmCtx->getDeclForMangledName(F.getName()); From f34d6adf4c8682a1718c9820e817ab9e76ec8a3b Mon Sep 17 00:00:00 2001 From: Julia Lapenko Date: Sat, 19 Dec 2020 00:15:26 +0600 Subject: [PATCH 09/10] [TSAR, Transform] Update the check for the availability of loop swapping. --- include/tsar/Support/DiagnosticKinds.td | 9 +- lib/Transform/Clang/LoopSwapping.cpp | 153 ++++++++++++++---------- 2 files changed, 96 insertions(+), 66 deletions(-) diff --git a/include/tsar/Support/DiagnosticKinds.td b/include/tsar/Support/DiagnosticKinds.td index 6c8c2637..c89c64e9 100644 --- a/include/tsar/Support/DiagnosticKinds.td +++ b/include/tsar/Support/DiagnosticKinds.td @@ -180,12 +180,15 @@ def error_expect_function_param : Error<"expected function parameter name">; def note_record_member_unknown: Error<"record has no member '%0'">; def note_declared_here: Note<"declared here">; -def warn_loop_swapping_diff_reduction: Warning<"unable to swap loops due to the different reduction types">; -def warn_loop_swapping_true_anti_dependence: Warning<"unable to swap loops due to the true or anti dependence">; +def warn_loop_swapping_diff_reduction: Warning<"unable to swap loops due to the different reduction kinds">; +def warn_loop_swapping_unknown_reduction: Warning<"unable to swap loops due to unknown reduction kind">; +def warn_loop_swapping_true_dependence: Warning<"unable to swap loops due to the true dependence">; +def warn_loop_swapping_anti_dependence: Warning<"unable to swap loops due to the anti dependence">; +def warn_loop_swapping_output_dependence: Warning<"unable to swap loops due to the output dependence">; def warn_loop_swapping_missing_loop: Warning<"not enough loops for swapping">; def warn_loop_swapping_redundant_loop: Warning<"too many loops for swapping, ignore redundant">; def warn_loop_swapping_no_loop_id: Warning<"cannot find loop ID to perform swapping">; def warn_loop_swapping_lost_loop: Warning<"cannot match ForStmt with its IR">; -def warn_loop_swapping_redundant_stmt: Warning<"pragma should only contain loops or other pragma">; +def error_loop_swapping_redundant_stmt: Error<"pragma should only contain loops or other pragma">; def error_loop_swapping_expect_compound: Error<"expected compound statement after pragma">; diff --git a/lib/Transform/Clang/LoopSwapping.cpp b/lib/Transform/Clang/LoopSwapping.cpp index 4c2c4a4a..a09e4102 100755 --- a/lib/Transform/Clang/LoopSwapping.cpp +++ b/lib/Transform/Clang/LoopSwapping.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include using namespace llvm; @@ -116,7 +117,7 @@ class LoopVisitor : public RecursiveASTVisitor { } if (mState == TraverseState::OUTERFOR && !dyn_cast(S)) { toDiag(mSrcMgr.getDiagnostics(), S->getBeginLoc(), - diag::warn_loop_swapping_redundant_stmt); + diag::error_loop_swapping_redundant_stmt); return false; } return RecursiveASTVisitor::TraverseStmt(S); @@ -172,9 +173,9 @@ class LoopVisitor : public RecursiveASTVisitor { dbgs() << "\tBegin:" << Range.getBegin().printToString(mSrcMgr) << "\n"; dbgs() << "\tEnd:" << Range.getEnd().printToString(mSrcMgr) <<"\n"; - dbgs() << "\t\n\t\t[Loop]\n"; + dbgs() << "\t\n\t[Loop]\n"; const auto &LoopText = mRewriter.getRewrittenText(Range); - dbgs() << "\t" << LoopText << "\n\n"; + dbgs() << LoopText << "\n\n"; } } } @@ -203,14 +204,18 @@ class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { void getAnalysisUsage(AnalysisUsage &AU) const override; private: + enum OutputDepKind : char { + Output = 0, + UnknownReduction, + DiffReduction, + SameReduction, + Private + }; void swapLoops(const LoopVisitor &Visitor); DIAliasTraitList getLoopTraits(MDNode *LoopID) const; bool isSwappingAvailable(const LoopRangeList &LRL, const Stmt *Pragma) const; - bool hasSameReductionKind(const DIAliasTraitList &TV0, - const DIAliasTraitList &TV1) const; - bool hasTrueOrAntiDependence(const DIAliasTraitList &TV0, - const DIAliasTraitList &TV1) const; - + OutputDepKind getOutputDepType(const DIAliasTrait *T0, + const DIAliasTrait *T1) const; Function *mFunction = nullptr; TransformationContext *mTfmCtx = nullptr; const GlobalOptions *mGlobalOpts = nullptr; @@ -260,54 +265,47 @@ DIAliasTraitList ClangLoopSwapping::getLoopTraits(MDNode *LoopID) const { return Traits; } -bool ClangLoopSwapping::hasSameReductionKind( - const DIAliasTraitList &TV0, const DIAliasTraitList &TV1) const { - for (auto &TS0: TV0) { - if (!TS0->is()) - continue; - auto *Node0 = TS0->getNode(); - for (auto &TS1: TV1) { - auto *Node1 = TS1->getNode(); - if (Node0 == Node1 && TS1->is()) { - LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: Same nodes with reduction.\n"); - auto *Red0 = (**TS0->begin()).get(); - auto *Red1 = (**TS1->begin()).get(); - if (!Red0 || !Red1) { - LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: Unknown Reduction.\n"); - return false; +ClangLoopSwapping::OutputDepKind ClangLoopSwapping::getOutputDepType( + const DIAliasTrait *T0, const DIAliasTrait *T1) const { + auto Kind = OutputDepKind::Output; + for (auto MemIt0 = T0->begin(); MemIt0 != T0->end(); MemIt0++) { + for (auto MemIt1 = T1->begin(); MemIt1 != T1->end(); MemIt1++) { + if ((*MemIt0)->getMemory() == (*MemIt1)->getMemory()) { + if ((**MemIt0).is() && (**MemIt1).is()){ + LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: Private.\n"); + Kind = OutputDepKind::Private; + continue; } - auto Kind0 = Red0->getKind(), Kind1 = Red1->getKind(); - if (Kind0 == trait::DIReduction::RK_NoReduction || - Kind1 == trait::DIReduction::RK_NoReduction) { - LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: Unknown Reduction.\n"); - return false; - } - if (Kind0 != Kind1) - return false; - } - } - } - return true; -} - -bool ClangLoopSwapping::hasTrueOrAntiDependence( - const DIAliasTraitList &TV0, const DIAliasTraitList &TV1) const { - SpanningTreeRelation STR(mDIAT); - for (auto &TS0: TV0) { - for (auto &TS1: TV1) { - if (!STR.isUnreachable(const_cast(TS0->getNode()), - const_cast(TS1->getNode()))) { - if (TS0->is() && !TS1->is()) { - // anti dependence - return true; - } else if (TS1->is() && !TS0->is()){ - // true dependence - return true; + auto *Red0 = (**MemIt0).get(); + auto *Red1 = (**MemIt1).get(); + auto Ind0 = (**MemIt0).is(); + auto Ind1 = (**MemIt1).is(); + if (Red0 && Red1) { + auto Kind0 = Red0->getKind(), Kind1 = Red1->getKind(); + if (Kind0 == trait::DIReduction::RK_NoReduction || + Kind1 == trait::DIReduction::RK_NoReduction) { + return OutputDepKind::UnknownReduction; + } + if (Kind0 != Kind1) + return OutputDepKind::DiffReduction; + Kind = OutputDepKind::SameReduction; + } else if ((Red0 && Ind1) || (Ind0 && Red1)) { + auto RedKind = Red0 ? Red0->getKind() : Red1->getKind(); + if (RedKind == trait::DIReduction::RK_NoReduction) + return OutputDepKind::UnknownReduction; + else if (!RedKind == trait::DIReduction::RK_Add) + return OutputDepKind::DiffReduction; + else + Kind = OutputDepKind::SameReduction; + } else if (Ind0 && Ind1) { + Kind = OutputDepKind::SameReduction; + } else { + return OutputDepKind::Output; } } } } - return false; + return Kind; } bool ClangLoopSwapping::isSwappingAvailable( @@ -327,19 +325,48 @@ bool ClangLoopSwapping::isSwappingAvailable( diag::warn_loop_swapping_no_loop_id); return false; } - auto Traits0 = getLoopTraits(LoopID0); - auto Traits1 = getLoopTraits(LoopID1); - if (!hasSameReductionKind(Traits0, Traits1)) { - toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), - diag::warn_loop_swapping_diff_reduction); - return false; - } - if (hasTrueOrAntiDependence(Traits0, Traits1)) { - toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), - diag::warn_loop_swapping_true_anti_dependence); - return false; + bool isAvailable = true; + SpanningTreeRelation STR(mDIAT); + for (auto &T0: getLoopTraits(LoopID0)) { + for (auto &T1: getLoopTraits(LoopID1)) { + if (STR.isUnreachable(T0->getNode(), T1->getNode())) + continue; + if (!T0->is() && T1->is()) { + toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), + diag::warn_loop_swapping_true_dependence); + isAvailable = false; + break; + } else if (T0->is() && !T1->is()) { + toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), + diag::warn_loop_swapping_anti_dependence); + isAvailable = false; + break; + } else if (!T0->is() && !T1->is()) { + auto OutDepKind = getOutputDepType(T0, T1); + LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: Output dependency kind: " << + OutDepKind << "\n"); + if (OutDepKind == OutputDepKind::Output) { + toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), + diag::warn_loop_swapping_output_dependence); + isAvailable = false; + break; + } else if (OutDepKind == OutputDepKind::DiffReduction) { + toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), + diag::warn_loop_swapping_diff_reduction); + isAvailable = false; + break; + } else if (OutDepKind == OutputDepKind::UnknownReduction) { + toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), + diag::warn_loop_swapping_unknown_reduction); + isAvailable = false; + break; + } + } + } + if (!isAvailable) + break; } - return true; + return isAvailable; } void ClangLoopSwapping::swapLoops(const LoopVisitor &Visitor) { From 4e86664af143cdc94a17fabc46f06e64ce204011 Mon Sep 17 00:00:00 2001 From: Julia Lapenko Date: Sun, 14 Feb 2021 19:15:02 +0600 Subject: [PATCH 10/10] [TSAR, Transform] Update diagnostic info for loop swapping and add tests. --- include/tsar/Support/DiagnosticKinds.td | 10 +-- lib/Transform/Clang/LoopSwapping.cpp | 68 +++++++++++++------ test/transform/CMakeLists.txt | 1 + test/transform/loopswap/CMakeLists.txt | 2 + test/transform/loopswap/check | 15 ++++ test/transform/loopswap/init | 15 ++++ test/transform/loopswap/loopswap_anti_1.c | 18 +++++ test/transform/loopswap/loopswap_anti_1.conf | 7 ++ test/transform/loopswap/loopswap_anti_1.tfm.c | 14 ++++ .../loopswap/loopswap_diff_cascade.c | 28 ++++++++ .../loopswap/loopswap_diff_cascade.conf | 7 ++ .../loopswap/loopswap_diff_cascade.tfm.c | 27 ++++++++ .../loopswap/loopswap_diff_reduction_1.c | 21 ++++++ .../loopswap/loopswap_diff_reduction_1.conf | 7 ++ .../loopswap/loopswap_diff_reduction_1.tfm.c | 16 +++++ .../loopswap/loopswap_expect_compound_1.c | 16 +++++ .../loopswap/loopswap_expect_compound_1.conf | 7 ++ .../loopswap/loopswap_expect_compound_1.tfm.c | 10 +++ .../loopswap/loopswap_independent_1.c | 16 +++++ .../loopswap/loopswap_independent_1.conf | 7 ++ .../loopswap/loopswap_independent_1.tfm.c | 15 ++++ .../loopswap/loopswap_missing_loop_1.c | 14 ++++ .../loopswap/loopswap_missing_loop_1.conf | 7 ++ .../loopswap/loopswap_missing_loop_1.tfm.c | 10 +++ test/transform/loopswap/loopswap_no_braces.c | 14 ++++ .../loopswap/loopswap_no_braces.conf | 7 ++ .../loopswap/loopswap_no_braces.tfm.c | 13 ++++ test/transform/loopswap/loopswap_output_1.c | 16 +++++ .../transform/loopswap/loopswap_output_1.conf | 7 ++ .../loopswap/loopswap_output_1.tfm.c | 11 +++ .../loopswap/loopswap_pragma_cascade.c | 42 ++++++++++++ .../loopswap/loopswap_pragma_cascade.conf | 7 ++ .../loopswap/loopswap_pragma_cascade.tfm.c | 41 +++++++++++ test/transform/loopswap/loopswap_private.c | 17 +++++ test/transform/loopswap/loopswap_private.conf | 7 ++ .../transform/loopswap/loopswap_private.tfm.c | 16 +++++ .../loopswap/loopswap_private_fake.c | 24 +++++++ .../loopswap/loopswap_private_fake.conf | 7 ++ .../loopswap/loopswap_private_fake.tfm.c | 20 ++++++ .../loopswap/loopswap_redundant_loop_1.c | 20 ++++++ .../loopswap/loopswap_redundant_loop_1.conf | 7 ++ .../loopswap/loopswap_redundant_loop_1.tfm.c | 16 +++++ .../loopswap/loopswap_redundant_stmt_1.c | 20 ++++++ .../loopswap/loopswap_redundant_stmt_1.conf | 7 ++ .../loopswap/loopswap_redundant_stmt_1.tfm.c | 14 ++++ .../loopswap/loopswap_same_reduction_1.c | 14 ++++ .../loopswap/loopswap_same_reduction_1.conf | 7 ++ .../loopswap/loopswap_same_reduction_1.tfm.c | 13 ++++ test/transform/loopswap/loopswap_true_1.c | 18 +++++ test/transform/loopswap/loopswap_true_1.conf | 7 ++ test/transform/loopswap/loopswap_true_1.tfm.c | 14 ++++ 51 files changed, 738 insertions(+), 26 deletions(-) create mode 100644 test/transform/loopswap/CMakeLists.txt create mode 100644 test/transform/loopswap/check create mode 100644 test/transform/loopswap/init create mode 100755 test/transform/loopswap/loopswap_anti_1.c create mode 100644 test/transform/loopswap/loopswap_anti_1.conf create mode 100755 test/transform/loopswap/loopswap_anti_1.tfm.c create mode 100644 test/transform/loopswap/loopswap_diff_cascade.c create mode 100644 test/transform/loopswap/loopswap_diff_cascade.conf create mode 100644 test/transform/loopswap/loopswap_diff_cascade.tfm.c create mode 100755 test/transform/loopswap/loopswap_diff_reduction_1.c create mode 100644 test/transform/loopswap/loopswap_diff_reduction_1.conf create mode 100755 test/transform/loopswap/loopswap_diff_reduction_1.tfm.c create mode 100755 test/transform/loopswap/loopswap_expect_compound_1.c create mode 100644 test/transform/loopswap/loopswap_expect_compound_1.conf create mode 100755 test/transform/loopswap/loopswap_expect_compound_1.tfm.c create mode 100644 test/transform/loopswap/loopswap_independent_1.c create mode 100644 test/transform/loopswap/loopswap_independent_1.conf create mode 100644 test/transform/loopswap/loopswap_independent_1.tfm.c create mode 100644 test/transform/loopswap/loopswap_missing_loop_1.c create mode 100644 test/transform/loopswap/loopswap_missing_loop_1.conf create mode 100644 test/transform/loopswap/loopswap_missing_loop_1.tfm.c create mode 100755 test/transform/loopswap/loopswap_no_braces.c create mode 100644 test/transform/loopswap/loopswap_no_braces.conf create mode 100644 test/transform/loopswap/loopswap_no_braces.tfm.c create mode 100644 test/transform/loopswap/loopswap_output_1.c create mode 100644 test/transform/loopswap/loopswap_output_1.conf create mode 100644 test/transform/loopswap/loopswap_output_1.tfm.c create mode 100755 test/transform/loopswap/loopswap_pragma_cascade.c create mode 100644 test/transform/loopswap/loopswap_pragma_cascade.conf create mode 100644 test/transform/loopswap/loopswap_pragma_cascade.tfm.c create mode 100644 test/transform/loopswap/loopswap_private.c create mode 100644 test/transform/loopswap/loopswap_private.conf create mode 100644 test/transform/loopswap/loopswap_private.tfm.c create mode 100644 test/transform/loopswap/loopswap_private_fake.c create mode 100644 test/transform/loopswap/loopswap_private_fake.conf create mode 100644 test/transform/loopswap/loopswap_private_fake.tfm.c create mode 100755 test/transform/loopswap/loopswap_redundant_loop_1.c create mode 100644 test/transform/loopswap/loopswap_redundant_loop_1.conf create mode 100644 test/transform/loopswap/loopswap_redundant_loop_1.tfm.c create mode 100644 test/transform/loopswap/loopswap_redundant_stmt_1.c create mode 100644 test/transform/loopswap/loopswap_redundant_stmt_1.conf create mode 100644 test/transform/loopswap/loopswap_redundant_stmt_1.tfm.c create mode 100755 test/transform/loopswap/loopswap_same_reduction_1.c create mode 100644 test/transform/loopswap/loopswap_same_reduction_1.conf create mode 100644 test/transform/loopswap/loopswap_same_reduction_1.tfm.c create mode 100755 test/transform/loopswap/loopswap_true_1.c create mode 100644 test/transform/loopswap/loopswap_true_1.conf create mode 100755 test/transform/loopswap/loopswap_true_1.tfm.c diff --git a/include/tsar/Support/DiagnosticKinds.td b/include/tsar/Support/DiagnosticKinds.td index c89c64e9..c1c412a3 100644 --- a/include/tsar/Support/DiagnosticKinds.td +++ b/include/tsar/Support/DiagnosticKinds.td @@ -180,11 +180,11 @@ def error_expect_function_param : Error<"expected function parameter name">; def note_record_member_unknown: Error<"record has no member '%0'">; def note_declared_here: Note<"declared here">; -def warn_loop_swapping_diff_reduction: Warning<"unable to swap loops due to the different reduction kinds">; -def warn_loop_swapping_unknown_reduction: Warning<"unable to swap loops due to unknown reduction kind">; -def warn_loop_swapping_true_dependence: Warning<"unable to swap loops due to the true dependence">; -def warn_loop_swapping_anti_dependence: Warning<"unable to swap loops due to the anti dependence">; -def warn_loop_swapping_output_dependence: Warning<"unable to swap loops due to the output dependence">; +def warn_loop_swapping_diff_reduction: Warning<"unable to swap loops due to different reduction kinds of variable '%0' declared at %1">; +def warn_loop_swapping_unknown_reduction: Warning<"unable to swap loops due to unknown reduction kind of variable '%0' declared at %1">; +def warn_loop_swapping_true_dependence: Warning<"unable to swap loops due to the true dependence of variable '%0' declared at %1">; +def warn_loop_swapping_anti_dependence: Warning<"unable to swap loops due to the anti dependence of variable '%0' declared at %1">; +def warn_loop_swapping_output_dependence: Warning<"unable to swap loops due to the output dependence of variable '%0' declared at %1">; def warn_loop_swapping_missing_loop: Warning<"not enough loops for swapping">; def warn_loop_swapping_redundant_loop: Warning<"too many loops for swapping, ignore redundant">; def warn_loop_swapping_no_loop_id: Warning<"cannot find loop ID to perform swapping">; diff --git a/lib/Transform/Clang/LoopSwapping.cpp b/lib/Transform/Clang/LoopSwapping.cpp index a09e4102..e07d99b8 100755 --- a/lib/Transform/Clang/LoopSwapping.cpp +++ b/lib/Transform/Clang/LoopSwapping.cpp @@ -24,8 +24,11 @@ #include "tsar/ADT/SpanningTreeRelation.h" #include "tsar/Analysis/AnalysisServer.h" +#include "tsar/Analysis/Clang/DIMemoryMatcher.h" #include "tsar/Analysis/Clang/LoopMatcher.h" #include "tsar/Analysis/Clang/NoMacroAssert.h" +#include "tsar/Analysis/Clang/VariableCollector.h" +#include "tsar/Analysis/Memory/ClonedDIMemoryMatcher.h" #include "tsar/Analysis/Memory/DIDependencyAnalysis.h" #include "tsar/Analysis/Memory/DIEstimateMemory.h" #include "tsar/Analysis/Memory/MemoryTraitUtils.h" @@ -42,7 +45,6 @@ #include #include #include -#include #include using namespace llvm; @@ -56,7 +58,8 @@ namespace { /// This provides access to function-level analysis results on server. using ClangLoopSwappingProvider = - FunctionPassAAProvider; + FunctionPassAAProvider; using DIAliasTraitList = SmallVector; using LoopRangeInfo = std::pair; using LoopRangeList = SmallVector; @@ -110,7 +113,6 @@ class LoopVisitor : public RecursiveASTVisitor { return true; } if (mState == TraverseState::PRAGMA && !dyn_cast(S)) { - S->dump(); toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), diag::error_loop_swapping_expect_compound); return false; @@ -213,7 +215,7 @@ class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { }; void swapLoops(const LoopVisitor &Visitor); DIAliasTraitList getLoopTraits(MDNode *LoopID) const; - bool isSwappingAvailable(const LoopRangeList &LRL, const Stmt *Pragma) const; + bool isSwappingAvailable(const LoopRangeList &LRL, const Stmt *Pragma); OutputDepKind getOutputDepType(const DIAliasTrait *T0, const DIAliasTrait *T1) const; Function *mFunction = nullptr; @@ -224,6 +226,10 @@ class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable { DIAliasTree *mDIAT = nullptr; std::function mGetLoopID; const SourceManager *mSrcMgr = nullptr; + const ClangDIMemoryMatcherPass::DIMemoryMatcher *mMemoryMatcher = nullptr; + const tsar::ClonedDIMemoryMatcher *mClonedMatcher = nullptr; + VariableCollector mASTVars; + }; class ClangLoopSwappingInfo final : public PassGroupInfo { @@ -235,6 +241,7 @@ class ClangLoopSwappingInfo final : public PassGroupInfo { Passes.add(createDIMemoryEnvironmentStorage()); Passes.add(createDIEstimateMemoryPass()); Passes.add(createDIMemoryAnalysisServer()); + Passes.add(createMemoryMatcherPass()); Passes.add(createAnalysisWaitServerPass()); Passes.add(createAnalysisWaitServerPass()); } @@ -309,7 +316,7 @@ ClangLoopSwapping::OutputDepKind ClangLoopSwapping::getOutputDepType( } bool ClangLoopSwapping::isSwappingAvailable( - const LoopRangeList &LRL, const Stmt *Pragma) const { + const LoopRangeList &LRL, const Stmt *Pragma) { auto ClientLoopID0 = LRL[0].first->getLoopID(); auto ClientLoopID1 = LRL[1].first->getLoopID(); assert(ClientLoopID0 && ClientLoopID1 && "LoopID must not be null!"); @@ -325,21 +332,29 @@ bool ClangLoopSwapping::isSwappingAvailable( diag::warn_loop_swapping_no_loop_id); return false; } - bool isAvailable = true; + bool IsAvailable = true; SpanningTreeRelation STR(mDIAT); + auto GetVarLoc = [this](VarDecl *VarDecl) -> std::string { + return VarDecl ? + VarDecl->getSourceRange().printToString(*mSrcMgr) : ""; + }; for (auto &T0: getLoopTraits(LoopID0)) { + clang::VarDecl *VarDecl = mASTVars.findDecl(*(*T0->begin())->getMemory(), + *mMemoryMatcher, *mClonedMatcher).first; for (auto &T1: getLoopTraits(LoopID1)) { if (STR.isUnreachable(T0->getNode(), T1->getNode())) continue; if (!T0->is() && T1->is()) { toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), - diag::warn_loop_swapping_true_dependence); - isAvailable = false; + diag::warn_loop_swapping_true_dependence) << + VarDecl->getName() << GetVarLoc(VarDecl); + IsAvailable = false; break; } else if (T0->is() && !T1->is()) { toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), - diag::warn_loop_swapping_anti_dependence); - isAvailable = false; + diag::warn_loop_swapping_anti_dependence) << + VarDecl->getName() << GetVarLoc(VarDecl); + IsAvailable = false; break; } else if (!T0->is() && !T1->is()) { auto OutDepKind = getOutputDepType(T0, T1); @@ -347,26 +362,29 @@ bool ClangLoopSwapping::isSwappingAvailable( OutDepKind << "\n"); if (OutDepKind == OutputDepKind::Output) { toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), - diag::warn_loop_swapping_output_dependence); - isAvailable = false; + diag::warn_loop_swapping_output_dependence) << + VarDecl->getName() << GetVarLoc(VarDecl); + IsAvailable = false; break; } else if (OutDepKind == OutputDepKind::DiffReduction) { toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), - diag::warn_loop_swapping_diff_reduction); - isAvailable = false; + diag::warn_loop_swapping_diff_reduction) << + VarDecl->getName() << GetVarLoc(VarDecl); + IsAvailable = false; break; } else if (OutDepKind == OutputDepKind::UnknownReduction) { toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), - diag::warn_loop_swapping_unknown_reduction); - isAvailable = false; + diag::warn_loop_swapping_unknown_reduction) << + VarDecl->getName() << GetVarLoc(VarDecl); + IsAvailable = false; break; } } } - if (!isAvailable) + if (!IsAvailable) break; } - return isAvailable; + return IsAvailable; } void ClangLoopSwapping::swapLoops(const LoopVisitor &Visitor) { @@ -425,16 +443,21 @@ bool ClangLoopSwapping::runOnFunction(Function &F) { auto *Socket = mSocketInfo->getActiveSocket(); auto RF = Socket->getAnalysis(F); - assert(RF && "Dependence analysis must be available for a parallel loop!"); + assert(RF && "Dependence analysis must be available!"); mDIAT = &RF->value()->getAliasTree(); mDIDepInfo = &RF->value()->getDependencies(); - auto R = Socket->getAnalysis(); - auto *Matcher = R->value(); + auto RM = Socket->getAnalysis(); + auto *Matcher = RM->value(); mGetLoopID = [Matcher](ObjectID ID) { auto ServerID = (*Matcher)->getMappedMD(ID); return ServerID ? cast(*ServerID) : nullptr; }; + auto *ServerF = cast((**Matcher)[&F]); + mClonedMatcher = + (**RM->value())[*ServerF]; auto &mLoopInfo = getAnalysis().getMatcher(); + mMemoryMatcher = &getAnalysis().getMatcher(); ASTImportInfo ImportStub; const auto *ImportInfo = &ImportStub; if (auto *ImportPass = getAnalysisIfAvailable()) @@ -460,6 +483,7 @@ void ClangLoopSwapping::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); AU.setPreservesAll(); } @@ -472,6 +496,7 @@ INITIALIZE_PROVIDER_BEGIN(ClangLoopSwappingProvider, "Loop Swapping (Clang, Provider)"); INITIALIZE_PASS_DEPENDENCY(DIDependencyAnalysisPass); INITIALIZE_PASS_DEPENDENCY(DIEstimateMemoryPass); +INITIALIZE_PASS_DEPENDENCY(ClonedDIMemoryMatcherWrapper); INITIALIZE_PROVIDER_END(ClangLoopSwappingProvider, "clang-loop-swapping-provider", "Loop Swapping (Clang, Provider)"); @@ -483,6 +508,7 @@ INITIALIZE_PASS_IN_GROUP_INFO(ClangLoopSwappingInfo); INITIALIZE_PASS_DEPENDENCY(AnalysisSocketImmutableWrapper); INITIALIZE_PASS_DEPENDENCY(TransformationEnginePass); INITIALIZE_PASS_DEPENDENCY(LoopMatcherPass); +INITIALIZE_PASS_DEPENDENCY(ClangDIMemoryMatcherPass); INITIALIZE_PASS_DEPENDENCY(GlobalOptionsImmutableWrapper); INITIALIZE_PASS_DEPENDENCY(ClangLoopSwappingProvider); INITIALIZE_PASS_IN_GROUP_END(ClangLoopSwapping,"clang-l-swap", diff --git a/test/transform/CMakeLists.txt b/test/transform/CMakeLists.txt index 0848b6f7..e1d76926 100644 --- a/test/transform/CMakeLists.txt +++ b/test/transform/CMakeLists.txt @@ -4,3 +4,4 @@ add_subdirectory(propagate) add_subdirectory(replace) add_subdirectory(openmp) add_subdirectory(dvmh_sm) +add_subdirectory(loopswap) diff --git a/test/transform/loopswap/CMakeLists.txt b/test/transform/loopswap/CMakeLists.txt new file mode 100644 index 00000000..f91596eb --- /dev/null +++ b/test/transform/loopswap/CMakeLists.txt @@ -0,0 +1,2 @@ +include(tsar-testing) +tsar_test(TARGET ClangLoopSwap PASSNAME "-clang-l-swap") diff --git a/test/transform/loopswap/check b/test/transform/loopswap/check new file mode 100644 index 00000000..d9129e59 --- /dev/null +++ b/test/transform/loopswap/check @@ -0,0 +1,15 @@ +loopswap_anti_1 +loopswap_true_1 +loopswap_diff_reduction_1 +loopswap_output_1 +loopswap_independent_1 +loopswap_same_reduction_1 +loopswap_missing_loop_1 +loopswap_redundant_loop_1 +loopswap_expect_compound_1 +loopswap_redundant_stmt_1 +loopswap_no_braces +loopswap_private_fake +loopswap_private +loopswap_pragma_cascade +loopswap_diff_cascade diff --git a/test/transform/loopswap/init b/test/transform/loopswap/init new file mode 100644 index 00000000..86b61ade --- /dev/null +++ b/test/transform/loopswap/init @@ -0,0 +1,15 @@ +loopswap_anti_1: action=init +loopswap_true_1: action=init +loopswap_diff_reduction_1: action=init +loopswap_output_1: action=init +loopswap_independent_1: action=init +loopswap_same_reduction_1: action=init +loopswap_missing_loop_1: action=init +loopswap_redundant_loop_1: action=init +loopswap_expect_compound_1: action=init +loopswap_redundant_stmt_1: action=init +loopswap_no_braces: action=init +loopswap_private_fake: action=init +loopswap_private: action=init +loopswap_pragma_cascade: action=init +loopswap_diff_cascade: action=init diff --git a/test/transform/loopswap/loopswap_anti_1.c b/test/transform/loopswap/loopswap_anti_1.c new file mode 100755 index 00000000..af9b5ca9 --- /dev/null +++ b/test/transform/loopswap/loopswap_anti_1.c @@ -0,0 +1,18 @@ +int f() { + int b = 18; + int sum = 0; +#pragma spf transform swaploops +{ + for (int i = 0; i < 7; i++) { + sum += b * i; + } + for (int j = 0; j < 5; j++) { + b += j * 10; + } +} + return sum - b; +} +//CHECK: loopswap_anti_1.c:4:9: warning: unable to swap loops due to the anti dependence of variable 'b' declared at +//CHECK: #pragma spf transform swaploops +//CHECK: ^ +//CHECK: 1 warning generated. diff --git a/test/transform/loopswap/loopswap_anti_1.conf b/test/transform/loopswap/loopswap_anti_1.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_anti_1.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_anti_1.tfm.c b/test/transform/loopswap/loopswap_anti_1.tfm.c new file mode 100755 index 00000000..94555f64 --- /dev/null +++ b/test/transform/loopswap/loopswap_anti_1.tfm.c @@ -0,0 +1,14 @@ +int f() { + int b = 18; + int sum = 0; +#pragma spf transform swaploops +{ + for (int i = 0; i < 7; i++) { + sum += b * i; + } + for (int j = 0; j < 5; j++) { + b += j * 10; + } +} + return sum - b; +} diff --git a/test/transform/loopswap/loopswap_diff_cascade.c b/test/transform/loopswap/loopswap_diff_cascade.c new file mode 100644 index 00000000..e66c35cf --- /dev/null +++ b/test/transform/loopswap/loopswap_diff_cascade.c @@ -0,0 +1,28 @@ +int f() { + int k = 7; +#pragma spf transform swaploops +{ + for (int n = 1; n < 10; n++) { + k *= 15; + } + #pragma spf transform swaploops + { + for (int i = 0; i < 10; i++) + k += (i + 1) * 4; + for (int j = 3; j < 7; j++) + k -= j * 12; + } + for (int m = 4; m < 15; m++) { + k *= m + 1; + } + #pragma spf transform swaploops + { + for (int i = 0; i < 10; i++) + k += (i + 1) * 4; + for (int j = 3; j < 7; j++) + k -= j * 12; + } +} + return k; +} +//CHECK: diff --git a/test/transform/loopswap/loopswap_diff_cascade.conf b/test/transform/loopswap/loopswap_diff_cascade.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_diff_cascade.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_diff_cascade.tfm.c b/test/transform/loopswap/loopswap_diff_cascade.tfm.c new file mode 100644 index 00000000..487760fd --- /dev/null +++ b/test/transform/loopswap/loopswap_diff_cascade.tfm.c @@ -0,0 +1,27 @@ +int f() { + int k = 7; +#pragma spf transform swaploops + { + for (int m = 4; m < 15; m++) { + k *= m + 1; + } +#pragma spf transform swaploops + { + for (int j = 3; j < 7; j++) + k -= j * 12; + for (int i = 0; i < 10; i++) + k += (i + 1) * 4; + } + for (int n = 1; n < 10; n++) { + k *= 15; + } +#pragma spf transform swaploops + { + for (int j = 3; j < 7; j++) + k -= j * 12; + for (int i = 0; i < 10; i++) + k += (i + 1) * 4; + } + } + return k; +} diff --git a/test/transform/loopswap/loopswap_diff_reduction_1.c b/test/transform/loopswap/loopswap_diff_reduction_1.c new file mode 100755 index 00000000..3105b025 --- /dev/null +++ b/test/transform/loopswap/loopswap_diff_reduction_1.c @@ -0,0 +1,21 @@ +int f() { + int acc = 0; + int sum = 100; +#pragma spf transform swaploops +{ + for (int i = 0; i < 7; ++i) { + acc += i + 10; + sum += i * 15; + } + for (int j = 1; j < 10; ++j) { + acc *= j; + sum -= j; + } +} + return acc + sum; +} + +//CHECK: loopswap_diff_reduction_1.c:4:9: warning: unable to swap loops due to different reduction kinds of variable 'acc' declared at +//CHECK: #pragma spf transform swaploops +//CHECK: ^ +//CHECK: 1 warning generated. diff --git a/test/transform/loopswap/loopswap_diff_reduction_1.conf b/test/transform/loopswap/loopswap_diff_reduction_1.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_diff_reduction_1.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_diff_reduction_1.tfm.c b/test/transform/loopswap/loopswap_diff_reduction_1.tfm.c new file mode 100755 index 00000000..94bfbdbd --- /dev/null +++ b/test/transform/loopswap/loopswap_diff_reduction_1.tfm.c @@ -0,0 +1,16 @@ +int f() { + int acc = 0; + int sum = 100; +#pragma spf transform swaploops +{ + for (int i = 0; i < 7; ++i) { + acc += i + 10; + sum += i * 15; + } + for (int j = 1; j < 10; ++j) { + acc *= j; + sum -= j; + } +} + return acc + sum; +} diff --git a/test/transform/loopswap/loopswap_expect_compound_1.c b/test/transform/loopswap/loopswap_expect_compound_1.c new file mode 100755 index 00000000..32d50646 --- /dev/null +++ b/test/transform/loopswap/loopswap_expect_compound_1.c @@ -0,0 +1,16 @@ +int f() { + int c = 0; +#pragma spf transform swaploops +int k = 5; +{ + for (int i = 0; i < 10; i++) + c += i; +} + return c; +} +//CHECK: Error while processing loopswap_expect_compound_1. +//CHECK: loopswap_expect_compound_1.c:3:23: error: expected compound statement after pragma +//CHECK: #pragma spf transform swaploops +//CHECK: ^ +//CHECK: 1 error generated. +//CHECK: Error while processing loopswap_expect_compound_1.c. diff --git a/test/transform/loopswap/loopswap_expect_compound_1.conf b/test/transform/loopswap/loopswap_expect_compound_1.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_expect_compound_1.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_expect_compound_1.tfm.c b/test/transform/loopswap/loopswap_expect_compound_1.tfm.c new file mode 100755 index 00000000..a8544539 --- /dev/null +++ b/test/transform/loopswap/loopswap_expect_compound_1.tfm.c @@ -0,0 +1,10 @@ +int f() { + int c = 0; +#pragma spf transform swaploops +int k = 5; +{ + for (int i = 0; i < 10; i++) + c += i; +} + return c; +} diff --git a/test/transform/loopswap/loopswap_independent_1.c b/test/transform/loopswap/loopswap_independent_1.c new file mode 100644 index 00000000..7e6e7593 --- /dev/null +++ b/test/transform/loopswap/loopswap_independent_1.c @@ -0,0 +1,16 @@ +int f() { + int a = 5, b = 1, c = 0, d = 4; +#pragma spf transform swaploops +{ + for (int i = 0; i < 10; i++) { + a += i; + b *= i * 2; + } + for (int j = 1; j < 7; j++) { + c += j; + d *= c * 3; + } +} + return a + b + c + d; +} +//CHECK: diff --git a/test/transform/loopswap/loopswap_independent_1.conf b/test/transform/loopswap/loopswap_independent_1.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_independent_1.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_independent_1.tfm.c b/test/transform/loopswap/loopswap_independent_1.tfm.c new file mode 100644 index 00000000..2f65786c --- /dev/null +++ b/test/transform/loopswap/loopswap_independent_1.tfm.c @@ -0,0 +1,15 @@ +int f() { + int a = 5, b = 1, c = 0, d = 4; +#pragma spf transform swaploops + { + for (int j = 1; j < 7; j++) { + c += j; + d *= c * 3; + } + for (int i = 0; i < 10; i++) { + a += i; + b *= i * 2; + } + } + return a + b + c + d; +} diff --git a/test/transform/loopswap/loopswap_missing_loop_1.c b/test/transform/loopswap/loopswap_missing_loop_1.c new file mode 100644 index 00000000..f470f3f1 --- /dev/null +++ b/test/transform/loopswap/loopswap_missing_loop_1.c @@ -0,0 +1,14 @@ +int f() { + int s = 0; +#pragma spf transform swaploops +{ + for (int i = 1; i < 10; i++) { + s += i * i; + } +} + return s; +} +//CHECK: loopswap_missing_loop_1.c:3:9: warning: not enough loops for swapping +//CHECK: #pragma spf transform swaploops +//CHECK: ^ +//CHECK: 1 warning generated. diff --git a/test/transform/loopswap/loopswap_missing_loop_1.conf b/test/transform/loopswap/loopswap_missing_loop_1.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_missing_loop_1.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_missing_loop_1.tfm.c b/test/transform/loopswap/loopswap_missing_loop_1.tfm.c new file mode 100644 index 00000000..108da9e6 --- /dev/null +++ b/test/transform/loopswap/loopswap_missing_loop_1.tfm.c @@ -0,0 +1,10 @@ +int f() { + int s = 0; +#pragma spf transform swaploops +{ + for (int i = 1; i < 10; i++) { + s += i * i; + } +} + return s; +} diff --git a/test/transform/loopswap/loopswap_no_braces.c b/test/transform/loopswap/loopswap_no_braces.c new file mode 100755 index 00000000..717f3584 --- /dev/null +++ b/test/transform/loopswap/loopswap_no_braces.c @@ -0,0 +1,14 @@ +int f() { + int sum = 0, res = 1; +#pragma spf transform swaploops +{ + for (int i = 0; i < 5; i++) { + sum += 2; + sum *= 1; + } + for (int j = 2; j < 10; j++) + res *= j; +} + return sum * res; +} +//CHECK: diff --git a/test/transform/loopswap/loopswap_no_braces.conf b/test/transform/loopswap/loopswap_no_braces.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_no_braces.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_no_braces.tfm.c b/test/transform/loopswap/loopswap_no_braces.tfm.c new file mode 100644 index 00000000..668ca3a7 --- /dev/null +++ b/test/transform/loopswap/loopswap_no_braces.tfm.c @@ -0,0 +1,13 @@ +int f() { + int sum = 0, res = 1; +#pragma spf transform swaploops + { + for (int j = 2; j < 10; j++) + res *= j; + for (int i = 0; i < 5; i++) { + sum += 2; + sum *= 1; + } + } + return sum * res; +} diff --git a/test/transform/loopswap/loopswap_output_1.c b/test/transform/loopswap/loopswap_output_1.c new file mode 100644 index 00000000..1977e1fd --- /dev/null +++ b/test/transform/loopswap/loopswap_output_1.c @@ -0,0 +1,16 @@ +int f() { + int k; +#pragma spf transform swaploops +{ + for (int i = 0; i < 10; ++i) + k = i; + for (int j = 0; j < 15; ++j) + k = j; +} + return k * 2; +} + +//CHECK: loopswap_output_1.c:3:9: warning: unable to swap loops due to the output dependence of variable 'k' declared at +//CHECK: #pragma spf transform swaploops +//CHECK: ^ +//CHECK: 1 warning generated. diff --git a/test/transform/loopswap/loopswap_output_1.conf b/test/transform/loopswap/loopswap_output_1.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_output_1.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_output_1.tfm.c b/test/transform/loopswap/loopswap_output_1.tfm.c new file mode 100644 index 00000000..3cba9abd --- /dev/null +++ b/test/transform/loopswap/loopswap_output_1.tfm.c @@ -0,0 +1,11 @@ +int f() { + int k, l; +#pragma spf transform swaploops + { + for (int j = 0; j < 15; ++j) + l = j; + for (int i = 0; i < 10; ++i) + k = i; + } + return k + l; +} diff --git a/test/transform/loopswap/loopswap_pragma_cascade.c b/test/transform/loopswap/loopswap_pragma_cascade.c new file mode 100755 index 00000000..ce317c94 --- /dev/null +++ b/test/transform/loopswap/loopswap_pragma_cascade.c @@ -0,0 +1,42 @@ +int f() { + int s = 0; +#pragma spf transform swaploops +{ + for (int i = 0; i < 10; i++) { + s += i; + } + for (int j = 1; j < 7; j++) { + s += j; + } + #pragma spf transform swaploops + { + for (int a = 0; a < 10; a++) { + s += a; + } + for (int b = 1; b < 7; b++) { + s -= b; + } + #pragma spf transform swaploops + { + for (int e = 0; e < 10; e++) { + s -= e; + } + for (int f = 1; f < 7; f++) { + s += f; + } + } + } +} + int r = 10; +#pragma spf transform swaploops +{ + for (int k = 0; k < 7; k++) { + r += 8 + k; + } + for (int l = 4; l < 10; l++) { + r += l; + } +} + return s + r; +} +//CHECK: diff --git a/test/transform/loopswap/loopswap_pragma_cascade.conf b/test/transform/loopswap/loopswap_pragma_cascade.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_pragma_cascade.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_pragma_cascade.tfm.c b/test/transform/loopswap/loopswap_pragma_cascade.tfm.c new file mode 100644 index 00000000..aad326fc --- /dev/null +++ b/test/transform/loopswap/loopswap_pragma_cascade.tfm.c @@ -0,0 +1,41 @@ +int f() { + int s = 0; +#pragma spf transform swaploops + { + for (int j = 1; j < 7; j++) { + s += j; + } + for (int i = 0; i < 10; i++) { + s += i; + } +#pragma spf transform swaploops + { + for (int b = 1; b < 7; b++) { + s -= b; + } + for (int a = 0; a < 10; a++) { + s += a; + } +#pragma spf transform swaploops + { + for (int f = 1; f < 7; f++) { + s += f; + } + for (int e = 0; e < 10; e++) { + s -= e; + } + } + } + } + int r = 10; +#pragma spf transform swaploops + { + for (int l = 4; l < 10; l++) { + r += l; + } + for (int k = 0; k < 7; k++) { + r += 8 + k; + } + } + return s + r; +} diff --git a/test/transform/loopswap/loopswap_private.c b/test/transform/loopswap/loopswap_private.c new file mode 100644 index 00000000..be55bcb7 --- /dev/null +++ b/test/transform/loopswap/loopswap_private.c @@ -0,0 +1,17 @@ +int f() { + int k = 0; + int sum = 0; +#pragma spf transform swaploops +{ + for (int i = 0; i < 10; i++) { + k = 7; + sum += i * i + k; + } + for (int j = 0; j < 10; j++) { + k = 8; + sum += j * j + k; + } +} + return sum; +} +//CHECK: diff --git a/test/transform/loopswap/loopswap_private.conf b/test/transform/loopswap/loopswap_private.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_private.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_private.tfm.c b/test/transform/loopswap/loopswap_private.tfm.c new file mode 100644 index 00000000..11fdd7f2 --- /dev/null +++ b/test/transform/loopswap/loopswap_private.tfm.c @@ -0,0 +1,16 @@ +int f() { + int k = 0; + int sum = 0; +#pragma spf transform swaploops + { + for (int j = 0; j < 10; j++) { + k = 8; + sum += j * j + k; + } + for (int i = 0; i < 10; i++) { + k = 7; + sum += i * i + k; + } + } + return sum; +} diff --git a/test/transform/loopswap/loopswap_private_fake.c b/test/transform/loopswap/loopswap_private_fake.c new file mode 100644 index 00000000..5fdb1add --- /dev/null +++ b/test/transform/loopswap/loopswap_private_fake.c @@ -0,0 +1,24 @@ +int f() { + int k = 0; + int sum = 0; +#pragma spf transform swaploops +{ + for (int i = 0; i < 10; i++) { + k = 0; + for (int l = 1; l < 7; l++) { + sum += i + l * k; + } + } + for (int j = 0; j < 10; j++) { + k = 7; + for (int l = 1; l < 7; l++) { + sum += j + l * k; + } + } +} + return 0; +} +//CHECK: loopswap_private_fake.c:4:9: warning: unable to swap loops due to the output dependence of variable 'sum' declared at +//CHECK: #pragma spf transform swaploops +//CHECK: ^ +//CHECK: 1 warning generated. diff --git a/test/transform/loopswap/loopswap_private_fake.conf b/test/transform/loopswap/loopswap_private_fake.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_private_fake.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_private_fake.tfm.c b/test/transform/loopswap/loopswap_private_fake.tfm.c new file mode 100644 index 00000000..6d49131f --- /dev/null +++ b/test/transform/loopswap/loopswap_private_fake.tfm.c @@ -0,0 +1,20 @@ +int f() { + int k = 0; + int sum = 0; +#pragma spf transform swaploops +{ + for (int i = 0; i < 10; i++) { + k = 0; + for (int l = 1; l < 7; l++) { + sum += i + l * k; + } + } + for (int j = 0; j < 10; j++) { + k = 7; + for (int l = 1; l < 7; l++) { + sum += j + l * k; + } + } +} + return 0; +} diff --git a/test/transform/loopswap/loopswap_redundant_loop_1.c b/test/transform/loopswap/loopswap_redundant_loop_1.c new file mode 100755 index 00000000..e3bb4f8f --- /dev/null +++ b/test/transform/loopswap/loopswap_redundant_loop_1.c @@ -0,0 +1,20 @@ +int f() { + int s = 0; +#pragma spf transform swaploops +{ + for (int i = 0; i < 10; ++i) { + s += i * 4; + } + for (int j = 0; j < 7; ++j) { + s -= j * 15; + } + for (int k = 4 ; k < 17; k += 3) { + s *= k; + } +} + return s; +} +//CHECK: loopswap_redundant_loop_1.c:3:9: warning: too many loops for swapping, ignore redundant +//CHECK: #pragma spf transform swaploops +//CHECK: ^ +//CHECK: 1 warning generated. diff --git a/test/transform/loopswap/loopswap_redundant_loop_1.conf b/test/transform/loopswap/loopswap_redundant_loop_1.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_redundant_loop_1.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_redundant_loop_1.tfm.c b/test/transform/loopswap/loopswap_redundant_loop_1.tfm.c new file mode 100644 index 00000000..9396baed --- /dev/null +++ b/test/transform/loopswap/loopswap_redundant_loop_1.tfm.c @@ -0,0 +1,16 @@ +int f() { + int s = 0; +#pragma spf transform swaploops + { + for (int j = 0; j < 7; ++j) { + s -= j * 15; + } + for (int i = 0; i < 10; ++i) { + s += i * 4; + } + for (int k = 4; k < 17; k += 3) { + s *= k; + } + } + return s; +} diff --git a/test/transform/loopswap/loopswap_redundant_stmt_1.c b/test/transform/loopswap/loopswap_redundant_stmt_1.c new file mode 100644 index 00000000..180f839b --- /dev/null +++ b/test/transform/loopswap/loopswap_redundant_stmt_1.c @@ -0,0 +1,20 @@ +int f() { + int s = 0; +#pragma spf transform swaploops +{ + s = 15; + for (int i = 0; i < 10; i++) { + s += i; + } + for (int k = 0; k < 15; k++) { + s += k; + } +} + return s; +} +//CHECK: Error while processing loopswap_redundant_stmt_1. +//CHECK: loopswap_redundant_stmt_1.c:5:2: error: pragma should only contain loops or other pragma +//CHECK: s = 15; +//CHECK: ^ +//CHECK: 1 error generated. +//CHECK: Error while processing loopswap_redundant_stmt_1.c. diff --git a/test/transform/loopswap/loopswap_redundant_stmt_1.conf b/test/transform/loopswap/loopswap_redundant_stmt_1.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_redundant_stmt_1.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_redundant_stmt_1.tfm.c b/test/transform/loopswap/loopswap_redundant_stmt_1.tfm.c new file mode 100644 index 00000000..b204889d --- /dev/null +++ b/test/transform/loopswap/loopswap_redundant_stmt_1.tfm.c @@ -0,0 +1,14 @@ +int f() { + int s = 0; +#pragma spf transform swaploops +{ + s = 15; + for (int i = 0; i < 10; i++) { + s += i; + } + for (int k = 0; k < 15; k++) { + s += k; + } +} + return s; +} diff --git a/test/transform/loopswap/loopswap_same_reduction_1.c b/test/transform/loopswap/loopswap_same_reduction_1.c new file mode 100755 index 00000000..b04b3d39 --- /dev/null +++ b/test/transform/loopswap/loopswap_same_reduction_1.c @@ -0,0 +1,14 @@ +int f() { + int sum = 0; +#pragma spf transform swaploops + { + for (int j = 0; j < 7; j++) { + sum -= j * 4; + } + for (int i = 0; i < 5; ++i) { + sum += i; + } + } + return sum; +} +//CHECK: diff --git a/test/transform/loopswap/loopswap_same_reduction_1.conf b/test/transform/loopswap/loopswap_same_reduction_1.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_same_reduction_1.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_same_reduction_1.tfm.c b/test/transform/loopswap/loopswap_same_reduction_1.tfm.c new file mode 100644 index 00000000..d0affdd2 --- /dev/null +++ b/test/transform/loopswap/loopswap_same_reduction_1.tfm.c @@ -0,0 +1,13 @@ +int f() { + int sum = 0; +#pragma spf transform swaploops + { + for (int i = 0; i < 5; ++i) { + sum += i; + } + for (int j = 0; j < 7; j++) { + sum -= j * 4; + } + } + return sum; +} diff --git a/test/transform/loopswap/loopswap_true_1.c b/test/transform/loopswap/loopswap_true_1.c new file mode 100755 index 00000000..01a4a199 --- /dev/null +++ b/test/transform/loopswap/loopswap_true_1.c @@ -0,0 +1,18 @@ +int f() { + int sum = 0; + int acc = 1; +#pragma spf transform swaploops +{ + for (int i = 0; i < 5; i++) { + sum += i; + } + for (int j = 1; j < 10; j++) { + acc = acc * j + sum; + } +} + return sum - acc; +} +//CHECK: loopswap_true_1.c:4:9: warning: unable to swap loops due to the true dependence of variable 'sum' declared at +//CHECK: #pragma spf transform swaploops +//CHECK: ^ +//CHECK: 1 warning generated. diff --git a/test/transform/loopswap/loopswap_true_1.conf b/test/transform/loopswap/loopswap_true_1.conf new file mode 100644 index 00000000..072bead5 --- /dev/null +++ b/test/transform/loopswap/loopswap_true_1.conf @@ -0,0 +1,7 @@ +plugin = TsarPlugin + +suffix = tfm +sample = $name.c +sample_diff = $name.$suffix.c +options = -clang-l-swap -output-suffix=$suffix +run = "$tsar $sample $options" diff --git a/test/transform/loopswap/loopswap_true_1.tfm.c b/test/transform/loopswap/loopswap_true_1.tfm.c new file mode 100755 index 00000000..b4b7dbf6 --- /dev/null +++ b/test/transform/loopswap/loopswap_true_1.tfm.c @@ -0,0 +1,14 @@ +int f() { + int sum = 0; + int acc = 1; +#pragma spf transform swaploops +{ + for (int i = 0; i < 5; i++) { + sum += i; + } + for (int j = 1; j < 10; j++) { + acc = acc * j + sum; + } +} + return sum - acc; +}