Skip to content

Commit 9c5f75d

Browse files
committed
[TSAR, Transform] Create loop swapping tranformation.
1 parent 1ba3c4c commit 9c5f75d

File tree

6 files changed

+291
-1
lines changed

6 files changed

+291
-1
lines changed

include/tsar/Support/Directives.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ def Propagate : Clause<"propagate", Transform>;
9797

9898
def Rename : Clause<"rename", Transform>;
9999

100+
def SwapLoops: Clause<"swaploops", Transform>;
101+
100102
def Private : Clause<"private", Analysis,
101103
[LParen, Identifier, ZeroOrMore<[Comma, Identifier]>, RParen]>;
102104

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#ifndef TSAR_CLANG_LOOP_SWAPPING_H
2+
#define TSAR_CLANG_LOOP_SWAPPING_H
3+
4+
#include "tsar/Transform/Clang/Passes.h"
5+
#include <bcl/utility.h>
6+
#include <llvm/Pass.h>
7+
8+
namespace llvm {
9+
10+
class ClangLoopSwapping : public FunctionPass, private bcl::Uncopyable {
11+
public:
12+
static char ID;
13+
14+
ClangLoopSwapping() : FunctionPass(ID) {
15+
initializeClangLoopSwappingPass(*PassRegistry::getPassRegistry());
16+
}
17+
18+
bool runOnFunction(Function &F) override;
19+
void getAnalysisUsage(AnalysisUsage &AU) const override;
20+
};
21+
}
22+
23+
#endif//TSAR_CLANG_LOOP_SWAPPING_H

include/tsar/Transform/Clang/Passes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,5 @@ void initializeClangOpenMPParalleizationPass(PassRegistry &Registry);
7878

7979
/// Create a pass to perform OpenMP-based parallelization.
8080
ModulePass* createClangOpenMPParallelization();
81-
}
81+
8282
#endif//TSAR_CLANG_TRANSFORM_PASSES_H

lib/Transform/Clang/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
set(TRANSFORM_SOURCES Passes.cpp ExprPropagation.cpp Inline.cpp RenameLocal.cpp
2+
<<<<<<< HEAD
3+
DeadDeclsElimination.cpp FormatPass.cpp LoopSwapping.cpp)
4+
=======
25
DeadDeclsElimination.cpp FormatPass.cpp OpenMPAutoPar.cpp)
6+
>>>>>>> upstream/master
37

48
if(MSVC_IDE)
59
file(GLOB_RECURSE TRANSFORM_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
//===- LoopSwapping.cpp - Source-level Renaming of Local Objects - *- C++ -*===//
2+
//
3+
// Traits Static Analyzer (SAPFOR)
4+
//
5+
// Copyright 2018 DVM System Group
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
//===----------------------------------------------------------------------===//
20+
//
21+
// The file declares a pass to perform swapping of specific loops.
22+
//
23+
//===----------------------------------------------------------------------===//
24+
25+
#include "tsar/Transform/Clang/LoopSwapping.h"
26+
#include "tsar/Analysis/Clang/GlobalInfoExtractor.h"
27+
#include "tsar/Analysis/Clang/LoopMatcher.h"
28+
#include "tsar/Analysis/Clang/NoMacroAssert.h"
29+
#include "tsar/Analysis/Clang/SourceLocationTraverse.h"
30+
#include "tsar/Core/Query.h"
31+
#include "tsar/Core/TransformationContext.h"
32+
#include "tsar/Support/Clang/Diagnostic.h"
33+
#include "tsar/Support/Clang/Pragma.h"
34+
#include <clang/AST/Decl.h>
35+
#include <clang/AST/RecursiveASTVisitor.h>
36+
#include <clang/AST/Stmt.h>
37+
#include <llvm/IR/Function.h>
38+
#include <llvm/Support/Debug.h>
39+
#include <llvm/Support/raw_ostream.h>
40+
#include <vector>
41+
#include <stack>
42+
43+
using namespace llvm;
44+
using namespace clang;
45+
using namespace tsar;
46+
47+
#undef DEBUG_TYPE
48+
#define DEBUG_TYPE "clang-l-swap"
49+
50+
char ClangLoopSwapping::ID = 0;
51+
52+
INITIALIZE_PASS_IN_GROUP_BEGIN(ClangLoopSwapping,"clang-l-swap",
53+
"'for' Loops Swapping (Clang)", false, false,
54+
tsar::TransformationQueryManager::getPassRegistry());
55+
INITIALIZE_PASS_IN_GROUP_INFO(LoopSwappingInfo);
56+
INITIALIZE_PASS_DEPENDENCY(TransformationEnginePass);
57+
INITIALIZE_PASS_DEPENDENCY(ClangGlobalInfoPass);
58+
INITIALIZE_PASS_DEPENDENCY(DIEstimateMemoryPass);
59+
INITIALIZE_PASS_DEPENDENCY(DIDependenceAnalysisPass);
60+
INITIALIZE_PASS_IN_GROUP_END(ClangLoopSwapping,"clang-l-swap",
61+
"'for' Loops Swapping (Clang)", false, false,
62+
tsar::TransformationQueryManager::getPassRegistry());
63+
64+
namespace {
65+
66+
class LoopSwapper : public RecursiveASTVisitor<LoopSwapper> {
67+
public:
68+
LoopSwapper(TransformationContext &TfmCtx,
69+
const ClangGlobalInfoPass::RawInfo &RawInfo,
70+
const GlobalInfoExtractor &GlobalInfo,
71+
const LoopMatcherPass::LoopMatcher &LM) :
72+
mTfmCtx(TfmCtx),
73+
mRawInfo(RawInfo),
74+
mGlobalInfo(GlobalInfo),
75+
mRewriter(TfmCtx.getRewriter()),
76+
mContext(TfmCtx.getContext()),
77+
mLoopInfo(&LM),
78+
mSrcMgr(TfmCtx.getRewriter().getSourceMgr()),
79+
mLangOpts(TfmCtx.getRewriter().getLangOpts()),
80+
mIsInScope(false), mForStack(nullptr) {}
81+
82+
void EnterInScope() {
83+
mForLocations.clear();
84+
mIsInScope = true;
85+
}
86+
87+
void ExitFromScope() {
88+
mForLocations.clear();
89+
mIsInScope = false;
90+
}
91+
92+
bool IsInScope() {
93+
return mIsInScope;
94+
}
95+
96+
bool TraverseStmt(Stmt *S) {
97+
if (!S)
98+
return true;
99+
Pragma P(*S);
100+
if (P) {
101+
// Search for loop swapping clause and disable renaming in other pragmas.
102+
if (findClause(P, ClauseId::SwapLoops, mClauses)) {
103+
llvm::SmallVector<clang::CharSourceRange, 8> ToRemove;
104+
auto IsPossible =
105+
pragmaRangeToRemove(P, mClauses, mSrcMgr, mLangOpts, ToRemove);
106+
if (!IsPossible.first)
107+
if (IsPossible.second & PragmaFlags::IsInMacro)
108+
toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getLocStart(),
109+
diag::warn_remove_directive_in_macro);
110+
else if (IsPossible.second & PragmaFlags::IsInHeader)
111+
toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getLocStart(),
112+
diag::warn_remove_directive_in_include);
113+
else
114+
toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getLocStart(),
115+
diag::warn_remove_directive);
116+
Rewriter::RewriteOptions RemoveEmptyLine;
117+
/// TODO ([email protected]): it seems that RemoveLineIfEmpty is
118+
/// set to true then removing (in RewriterBuffer) works incorrect.
119+
RemoveEmptyLine.RemoveLineIfEmpty = false;
120+
for (auto SR : ToRemove)
121+
mRewriter.RemoveText(SR, RemoveEmptyLine);
122+
EnterInScope();
123+
}
124+
return true;
125+
}
126+
auto Res = RecursiveASTVisitor::TraverseStmt(S);
127+
return Res;
128+
}
129+
130+
bool TraverseCompoundStmt(CompoundStmt *S) {
131+
if (IsInScope() && mForStack == nullptr) {
132+
mForStack = new std::stack<ForStmt *>;
133+
mForLocations.clear();
134+
auto Res = RecursiveASTVisitor::TraverseCompoundStmt(S);
135+
while (!mForStack->empty())
136+
mForStack->pop();
137+
delete mForStack;
138+
mForStack = nullptr;
139+
mForPairs.push_back(mForLocations);
140+
ExitFromScope();
141+
return Res;
142+
}
143+
return RecursiveASTVisitor::TraverseCompoundStmt(S);
144+
}
145+
146+
bool TraverseForStmt(ForStmt *S) {
147+
auto Match = mLoopInfo->find<AST>(For);
148+
if (IsInScope() && mForStack != nullptr) {
149+
if (mForStack->empty()) {
150+
SourceRange range(S->getBeginLoc(), S->getEndLoc());
151+
mForLocations.push_back(range);
152+
mForStack->push(S);
153+
auto Res = RecursiveASTVisitor::TraverseForStmt(S);
154+
mForStack->pop();
155+
return Res;
156+
}
157+
}
158+
return RecursiveASTVisitor::TraverseForStmt(S);
159+
}
160+
161+
void SwapLoops() {
162+
for (auto pair: mForPairs) {
163+
if (pair.size() < 2) {
164+
outs() << "Too few loops for swap. Ignore.\n";
165+
continue;
166+
}
167+
if (pair.size() > 2) {
168+
outs() << "Too many loops for swap. Additional loops will be ignored.\n";
169+
}
170+
SourceRange first = pair[0];
171+
SourceRange second = pair[1];
172+
std::string first_loop = mRewriter.getRewrittenText(first);
173+
std::string second_loop = mRewriter.getRewrittenText(second);
174+
outs() << "First loop: \n";
175+
outs() << first_loop << "\n";
176+
outs() << "Second loop: \n";
177+
outs() << second_loop << "\n";
178+
mRewriter.ReplaceText(first, second_loop);
179+
mRewriter.ReplaceText(second, first_loop);
180+
}
181+
}
182+
183+
void PrintLocations() {
184+
outs() << "'for' loop locations:\n";
185+
for (auto location : mForLocations) {
186+
SourceLocation begin = location.getBegin();
187+
SourceLocation end = location.getEnd();
188+
outs() << "Begin: ";
189+
begin.print(outs(), mSrcMgr);
190+
outs() << "; End: ";
191+
end.print(outs(), mSrcMgr);
192+
outs() << '\n';
193+
}
194+
}
195+
196+
private:
197+
TransformationContext &mTfmCtx;
198+
Rewriter &mRewriter;
199+
ASTContext &mContext;
200+
SourceManager &mSrcMgr;
201+
const LangOptions &mLangOpts;
202+
const ClangGlobalInfoPass::RawInfo &mRawInfo;
203+
const GlobalInfoExtractor &mGlobalInfo;
204+
bool mIsInScope;
205+
const LoopMatcherPass::LoopMatcher *mLoopInfo;
206+
207+
SmallVector<Stmt *, 1> mClauses;
208+
std::vector<SourceRange> mForLocations;
209+
std::vector<std::vector<SourceRange>> mForPairs;
210+
std::stack<ForStmt *> *mForStack;
211+
};
212+
213+
class ClangLoopSwappingInfo final : public PassGroupInfo {
214+
void addBeforePass(legacy::PassManager &Passes) const override {
215+
addImmutableAliasAnalysis(Passes);
216+
addInitialTransformations(Passes);
217+
Passes.add(createDIMemoryTraitPoolStorage());
218+
Passes.add(createDIMemoryEnvironmentStorage());
219+
}
220+
void addAfterPass(legacy::PassManager &Passes) const override {
221+
Passes.add(createAnalysisReleaseServerPass());
222+
Passes.add(createAnalysisCloseConnectionPass());
223+
}
224+
225+
};
226+
227+
}
228+
229+
bool ClangLoopSwapping::runOnFunction(Function &F) {
230+
auto *M = F.getParent();
231+
auto mTfmCtx = getAnalysis<TransformationEnginePass>().getContext(*M);
232+
if (!mTfmCtx || !mTfmCtx->hasInstance()) {
233+
M->getContext().emitError("can not transform sources"
234+
": transformation context is not available");
235+
return false;
236+
}
237+
auto FuncDecl = mTfmCtx->getDeclForMangledName(F.getName());
238+
if (!FuncDecl)
239+
return false;
240+
auto &GIP = getAnalysis<ClangGlobalInfoPass>();
241+
LoopSwapper sw(*mTfmCtx, GIP.getRawInfo(), GIP.getGlobalInfo());
242+
sw.TraverseDecl(FuncDecl);
243+
//sw.PrintLocations();
244+
sw.SwapLoops();
245+
return false;
246+
}
247+
248+
void ClangLoopSwapping::getAnalysisUsage(AnalysisUsage &AU) const {
249+
AU.addRequired<TransformationEnginePass>();
250+
AU.addRequired<ClangGlobalInfoPass>();
251+
AU.setPreservesAll();
252+
}
253+
254+
FunctionPass * llvm::createClangLoopSwapping() {
255+
return new ClangLoopSwapping();
256+
}
257+

lib/Transform/Clang/Passes.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,9 @@ void llvm::initializeClangTransform(PassRegistry &Registry) {
3333
initializeClangInlinerPassPass(Registry);
3434
initializeClangRenameLocalPassPass(Registry);
3535
initializeClangDeadDeclsEliminationPass(Registry);
36+
<<<<<<< HEAD
37+
initializeClangLoopSwappingPass(Registry);
38+
=======
3639
initializeClangOpenMPParalleizationPass(Registry);
40+
>>>>>>> upstream/master
3741
}

0 commit comments

Comments
 (0)