diff --git a/include/tsar/Support/DiagnosticKinds.td b/include/tsar/Support/DiagnosticKinds.td index 4b57f059..c1c412a3 100644 --- a/include/tsar/Support/DiagnosticKinds.td +++ b/include/tsar/Support/DiagnosticKinds.td @@ -179,3 +179,16 @@ 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 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">; +def warn_loop_swapping_lost_loop: Warning<"cannot match ForStmt with its IR">; +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/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/Passes.h b/include/tsar/Transform/Clang/Passes.h index 250f08da..c6ef10d3 100644 --- a/include/tsar/Transform/Clang/Passes.h +++ b/include/tsar/Transform/Clang/Passes.h @@ -92,5 +92,13 @@ 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(); + +/// 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 100755 index 00000000..e07d99b8 --- /dev/null +++ b/lib/Transform/Clang/LoopSwapping.cpp @@ -0,0 +1,516 @@ +//===- LoopSwapping.cpp - Loop Swapping (Clang) -----------------*- C++ -*-===// +// +// Traits Static Analyzer (SAPFOR) +// +// 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. +// 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/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" +#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" +#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 + +using namespace llvm; +using namespace clang; +using namespace tsar; + +#undef DEBUG_TYPE +#define DEBUG_TYPE "clang-l-swap" + +namespace { + +/// This provides access to function-level analysis results on server. +using ClangLoopSwappingProvider = + FunctionPassAAProvider; +using DIAliasTraitList = SmallVector; +using LoopRangeInfo = std::pair; +using LoopRangeList = SmallVector; +using PragmaInfoList = DenseMap; + +class LoopVisitor : public RecursiveASTVisitor { +private: + enum TraverseState { NONE, PRAGMA, OUTERFOR, INNERFOR }; +public: + 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) + {} + + 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)) { + SmallVector ToRemove; + auto IsPossible = + pragmaRangeToRemove(P, mClauses, mSrcMgr, mLangOpts, mImportInfo, + ToRemove); + if (!IsPossible.first) + if (IsPossible.second & PragmaFlags::IsInMacro) + toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), + diag::warn_remove_directive_in_macro); + else if (IsPossible.second & PragmaFlags::IsInHeader) + toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), + diag::warn_remove_directive_in_include); + else + toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), + 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);*/ + mPragmaLoopsInfo.insert(std::make_pair(S, LoopRangeList())); + mPragmaStack.push(S); + mState = TraverseState::PRAGMA; + } + return true; + } + if (mState == TraverseState::PRAGMA && !dyn_cast(S)) { + toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), + 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) { + if (mState == TraverseState::PRAGMA) { + mState = TraverseState::OUTERFOR; + auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S); + mPragmaStack.pop(); + mState = mPragmaStack.empty() ? TraverseState::NONE : TraverseState::OUTERFOR; + 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[mPragmaStack.top()]; + LRL.push_back(std::make_pair(Match->get(), S->getSourceRange())); + } else { + toDiag(mSrcMgr.getDiagnostics(), S->getBeginLoc(), + diag::warn_loop_swapping_lost_loop); + } + mState = TraverseState::INNERFOR; + auto Res = RecursiveASTVisitor::TraverseForStmt(S); + mState = TraverseState::OUTERFOR; + return Res; + } + return RecursiveASTVisitor::TraverseForStmt(S); + } + + const PragmaInfoList &getPragmaLoopsInfo() const { + return mPragmaLoopsInfo; + } + + bool hasPragma() const { + return !mPragmaLoopsInfo.empty(); + } + + #ifdef LLVM_DEBUG + void printLocations() const { + int N = 0; + for (auto It = mPragmaLoopsInfo.begin(); It != mPragmaLoopsInfo.end(); + ++It, ++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[Range]\n"; + dbgs() << "\tBegin:" << Range.getBegin().printToString(mSrcMgr) + << "\n"; + dbgs() << "\tEnd:" << Range.getEnd().printToString(mSrcMgr) <<"\n"; + dbgs() << "\t\n\t[Loop]\n"; + const auto &LoopText = mRewriter.getRewrittenText(Range); + dbgs() << LoopText << "\n\n"; + } + } + } + #endif + +private: + Rewriter &mRewriter; + SourceManager &mSrcMgr; + const ASTImportInfo &mImportInfo; + const LangOptions &mLangOpts; + const LoopMatcherPass::LoopMatcher &mLoopInfo; + TraverseState mState; + SmallVector mClauses; + PragmaInfoList mPragmaLoopsInfo; + std::stack mPragmaStack; +}; + +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: + 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); + OutputDepKind getOutputDepType(const DIAliasTrait *T0, + const DIAliasTrait *T1) 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; + const ClangDIMemoryMatcherPass::DIMemoryMatcher *mMemoryMatcher = nullptr; + const tsar::ClonedDIMemoryMatcher *mClonedMatcher = nullptr; + VariableCollector mASTVars; + +}; + +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(createDIMemoryAnalysisServer()); + Passes.add(createMemoryMatcherPass()); + Passes.add(createAnalysisWaitServerPass()); + Passes.add(createAnalysisWaitServerPass()); + } + + void addAfterPass(legacy::PassManager &Passes) const override { + Passes.add(createAnalysisReleaseServerPass()); + Passes.add(createAnalysisCloseConnectionPass()); + } +}; + +} //namespace + +char ClangLoopSwapping::ID = 0; + +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); + DIAliasTraitList Traits; + for (auto &TS : DIDepSet) { + if (!Coverage.count(TS.getNode())) + continue; + Traits.push_back(&TS); + } + return Traits; +} + +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 *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 Kind; +} + +bool ClangLoopSwapping::isSwappingAvailable( + 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!"); + auto *LoopID0 = mGetLoopID(ClientLoopID0); + auto *LoopID1 = mGetLoopID(ClientLoopID1); + if (!LoopID0) { + toDiag(mSrcMgr->getDiagnostics(), LRL[0].second.getBegin(), + diag::warn_loop_swapping_no_loop_id); + return false; + } + if (!LoopID1) { + toDiag(mSrcMgr->getDiagnostics(), LRL[1].second.getBegin(), + diag::warn_loop_swapping_no_loop_id); + return false; + } + 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) << + VarDecl->getName() << GetVarLoc(VarDecl); + IsAvailable = false; + break; + } else if (T0->is() && !T1->is()) { + toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), + diag::warn_loop_swapping_anti_dependence) << + VarDecl->getName() << GetVarLoc(VarDecl); + 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) << + VarDecl->getName() << GetVarLoc(VarDecl); + IsAvailable = false; + break; + } else if (OutDepKind == OutputDepKind::DiffReduction) { + toDiag(mSrcMgr->getDiagnostics(), Pragma->getBeginLoc(), + 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) << + VarDecl->getName() << GetVarLoc(VarDecl); + IsAvailable = false; + break; + } + } + } + if (!IsAvailable) + break; + } + return IsAvailable; +} + +void ClangLoopSwapping::swapLoops(const LoopVisitor &Visitor) { + Rewriter &Rewr = mTfmCtx->getRewriter(); + 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 &PragmaLoopsInfo = Visitor.getPragmaLoopsInfo(); + 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); + } + } +} + +bool ClangLoopSwapping::runOnFunction(Function &F) { + mFunction = &F; + auto *M = F.getParent(); + 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"); + return false; + } + auto FuncDecl = mTfmCtx->getDeclForMangledName(F.getName()); + if (!FuncDecl) + return false; + mSocketInfo = &getAnalysis().get(); + mGlobalOpts = &getAnalysis().getOptions(); + auto *Socket = mSocketInfo->getActiveSocket(); + auto RF = + Socket->getAnalysis(F); + assert(RF && "Dependence analysis must be available!"); + mDIAT = &RF->value()->getAliasTree(); + mDIDepInfo = &RF->value()->getDependencies(); + 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()) + ImportInfo = &ImportPass->getImportInfo(); + LoopVisitor Visitor(mTfmCtx->getRewriter(), mLoopInfo, *ImportInfo); + mSrcMgr = &mTfmCtx->getRewriter().getSourceMgr(); + Visitor.TraverseDecl(FuncDecl); + if (mSrcMgr->getDiagnostics().hasErrorOccurred()) + return false; + if (!Visitor.hasPragma()) { + LLVM_DEBUG(dbgs() << "[LOOP SWAPPING]: no pragma found.\n"); + return false; + } + LLVM_DEBUG(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.setPreservesAll(); +} + +FunctionPass * llvm::createClangLoopSwapping() { + return new ClangLoopSwapping(); +} + +INITIALIZE_PROVIDER_BEGIN(ClangLoopSwappingProvider, + "clang-loop-swapping-provider", + "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)"); + +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(ClangDIMemoryMatcherPass); +INITIALIZE_PASS_DEPENDENCY(GlobalOptionsImmutableWrapper); +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 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); } 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; +}