-
Notifications
You must be signed in to change notification settings - Fork 18
Remove-firstprivate pass #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 12 commits
1759c61
bfd9a01
1d9d69d
1a63251
6e9f702
945641d
34fb122
338cdb3
c50822d
7386e89
522e71c
1114bfe
1c44b9f
906f162
5d8c0c4
05e69bf
24b8cae
67e4ca4
090c25d
a543fc0
43c9f2f
19f6aea
8d89107
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,349 @@ | ||
//=== RemoveFirstPrivate.cpp - RFP (Clang) --*- C++ -*===// | ||
// | ||
// Traits Static Analyzer (SAPFOR) | ||
// | ||
// Copyright 2018 DVM System Group | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file implements a pass to initialize firstprivate variables. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "tsar/Analysis/Clang/GlobalInfoExtractor.h" | ||
#include "tsar/Analysis/Clang/NoMacroAssert.h" | ||
#include "tsar/Core/Query.h" | ||
#include "tsar/Frontend/Clang/TransformationContext.h" | ||
#include "tsar/Support/Clang/Diagnostic.h" | ||
#include <clang/AST/Decl.h> | ||
#include <clang/AST/RecursiveASTVisitor.h> | ||
#include <clang/AST/Stmt.h> | ||
#include "tsar/Analysis/Memory/Utils.h" | ||
#include "tsar/Support/MetadataUtils.h" | ||
#include <clang/Basic/SourceLocation.h> | ||
#include <llvm/ADT/SmallVector.h> | ||
#include <llvm/IR/Function.h> | ||
#include <llvm/IR/Module.h> | ||
#include <llvm/Support/Debug.h> | ||
#include <llvm/Support/raw_ostream.h> | ||
#include "tsar/Transform/Clang/Passes.h" | ||
#include <bcl/utility.h> | ||
#include <llvm/Pass.h> | ||
#include <stack> | ||
|
||
using namespace clang; | ||
using namespace llvm; | ||
using namespace tsar; | ||
|
||
#undef DEBUG_TYPE | ||
#define DEBUG_TYPE "clang-rfp" | ||
|
||
static int getDimensionsNum(QualType qt, std::vector<int>& default_dimensions) { | ||
int res = 0; | ||
bool sizeIsKnown = true; | ||
while(1) { | ||
if (qt -> isArrayType()) { | ||
auto at = qt -> getAsArrayTypeUnsafe(); | ||
auto t = dyn_cast_or_null<ConstantArrayType>(at); | ||
if (sizeIsKnown && t) { // get size | ||
uint64_t dim = t -> getSize().getLimitedValue(); | ||
default_dimensions.push_back(dim); | ||
} | ||
qt = at -> getElementType(); | ||
res++; | ||
} else if (qt -> isPointerType()) { | ||
sizeIsKnown = false; | ||
qt = qt -> getPointeeType(); | ||
res++; | ||
} else { | ||
return res; | ||
} | ||
} | ||
} | ||
|
||
namespace { | ||
|
||
class ClangRemoveFirstPrivate : public FunctionPass, private bcl::Uncopyable { | ||
public: | ||
static char ID; | ||
|
||
ClangRemoveFirstPrivate() : FunctionPass(ID) { | ||
initializeClangRemoveFirstPrivatePass(*PassRegistry::getPassRegistry()); | ||
} | ||
|
||
bool runOnFunction(Function &F) override; | ||
void getAnalysisUsage(AnalysisUsage &AU) const override; | ||
}; | ||
|
||
struct vars { // contains information about variables in | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
bool rvalIsArray = false; // removefirstprivate clause | ||
std::string lvalName; | ||
std::string rvalName; | ||
int dimensionsNum; | ||
std::vector<int> dimensions; | ||
std::vector<int> default_dimensions; | ||
}; | ||
} | ||
|
||
char ClangRemoveFirstPrivate::ID = 0; | ||
|
||
INITIALIZE_PASS_IN_GROUP_BEGIN(ClangRemoveFirstPrivate, "remove-firstprivate", | ||
"Initialize variables in for", false, false, | ||
TransformationQueryManager::getPassRegistry()) | ||
INITIALIZE_PASS_DEPENDENCY(TransformationEnginePass) | ||
INITIALIZE_PASS_DEPENDENCY(ClangGlobalInfoPass) | ||
INITIALIZE_PASS_IN_GROUP_END(ClangRemoveFirstPrivate, "remove-firstprivate", | ||
"Initialize variables in for", false, false, | ||
TransformationQueryManager::getPassRegistry()) | ||
|
||
namespace { | ||
|
||
class DeclVisitor : public RecursiveASTVisitor<DeclVisitor> { | ||
|
||
struct DeclarationInfo { | ||
DeclarationInfo(Stmt *S) : Scope(S) {} | ||
|
||
Stmt *Scope; | ||
}; | ||
public: | ||
explicit DeclVisitor(TransformationContext &TfmCtx, const ASTImportInfo &ImportInfo, | ||
ClangGlobalInfoPass::RawInfo &RawInfo) : | ||
mTfmCtx(&TfmCtx), mImportInfo(ImportInfo), | ||
mRawInfo(&RawInfo), mRewriter(TfmCtx.getRewriter()), | ||
mContext(TfmCtx.getContext()), mSrcMgr(mRewriter.getSourceMgr()), | ||
mLangOpts(mRewriter.getLangOpts()) {} | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
bool TraverseStmt(Stmt *S) { | ||
if (!S) | ||
return true; | ||
|
||
bool ast = false; | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Pragma P(*S); | ||
|
||
if (findClause(P, ClauseId::RemoveFirstPrivate, mClauses)) { | ||
auto locationForInits = S -> getEndLoc(); | ||
isInPragma = true; | ||
ast = RecursiveASTVisitor::TraverseStmt(S); | ||
isInPragma = false; | ||
|
||
std::string txtStr, beforeFor, forBody, lval, rval, indeces; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Эти строки скорее всего маленькие, лучше использовать |
||
std::vector<std::string> inits; | ||
while (varStack.size()) { | ||
if (varStack.top().dimensionsNum) { // lvalue is array | ||
if (varStack.top().dimensions.size() < varStack.top().dimensionsNum) { | ||
if (varStack.top().default_dimensions.size() == varStack.top().dimensionsNum) { | ||
varStack.top().dimensions = varStack.top().default_dimensions; | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} else { | ||
varStack.pop(); | ||
continue; // dimensions ar mandatory for arrays, skip | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} // initialization if no dimensions found | ||
} | ||
forBody = std::string(); | ||
indeces = std::string(); | ||
lval = varStack.top().lvalName; | ||
rval = varStack.top().rvalName; | ||
txtStr = std::string(); | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for (std::vector<int>::iterator it = varStack.top().dimensions.begin(); | ||
it != varStack.top().dimensions.end(); | ||
it ++) { | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
int intCounter = it - varStack.top().dimensions.begin(); | ||
std::string strCounter = "i" + std::to_string(intCounter); | ||
indeces += "[" + strCounter + "]"; | ||
txtStr += "for (int " + strCounter + " = 0; " + strCounter + " < " + | ||
std::to_string(*it) + "; " + strCounter + "++) {\n"; | ||
} | ||
if (varStack.top().rvalIsArray) { | ||
rval += indeces; | ||
} | ||
lval += indeces; | ||
forBody = lval + " = " + rval + ";\n"; | ||
txtStr += forBody; | ||
for (int i = 0; i < varStack.top().dimensionsNum; i++) { | ||
txtStr += "}\n"; | ||
} | ||
} else { // Initialize non-array variable | ||
txtStr = varStack.top().lvalName + " = " + varStack.top().rvalName + ";\n"; | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
inits.push_back(txtStr); | ||
varStack.pop(); | ||
} | ||
|
||
llvm::SmallVector<clang::CharSourceRange, 8> ToRemove; | ||
auto IsPossible = pragmaRangeToRemove(P, mClauses, mSrcMgr, mLangOpts, | ||
mImportInfo, ToRemove); | ||
if (!IsPossible.first) | ||
if (IsPossible.second & PragmaFlags::IsInMacro) | ||
toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), | ||
tsar::diag::warn_remove_directive_in_macro); | ||
else if (IsPossible.second & PragmaFlags::IsInHeader) | ||
toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), | ||
tsar::diag::warn_remove_directive_in_include); | ||
else | ||
toDiag(mSrcMgr.getDiagnostics(), mClauses.front()->getBeginLoc(), | ||
tsar::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); // delete each range | ||
|
||
for (std::vector<std::string>::iterator it = inits.begin(); it != inits.end(); ++it) { | ||
mRewriter.InsertTextAfterToken(locationForInits, *it); | ||
} | ||
return ast; | ||
} | ||
return RecursiveASTVisitor::TraverseStmt(S); | ||
} | ||
|
||
bool TraverseDeclRefExpr(clang::DeclRefExpr *Ex) { | ||
std::string varName; | ||
if (isInPragma) { | ||
if (waitingForDimensions && curDimensionNum == varStack.top().dimensionsNum) { | ||
waitingForDimensions = false; | ||
curDimensionNum = 0; | ||
} | ||
if (auto *Var{dyn_cast<VarDecl>(Ex->getDecl())}) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. А что будет, если там не переменная, а что-то другое. Имя функции, структуры, |
||
varName = Var -> getName(); | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
if (waitingForVar) { // get lvalue | ||
ValueDecl *vd = Ex -> getDecl(); | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
QualType qt = vd -> getType(); | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
vars tmp; | ||
|
||
tmp.lvalName = varName; | ||
varStack.push(tmp); | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
varStack.top().dimensionsNum = getDimensionsNum(qt, varStack.top().default_dimensions); | ||
waitingForDimensions = false; | ||
} else { // get rvalue | ||
ValueDecl *vd = Ex -> getDecl(); | ||
QualType qt = vd -> getType(); | ||
if (qt -> isArrayType() || qt -> isPointerType()) { | ||
varStack.top().rvalIsArray = true; | ||
} | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
varStack.top().rvalName = varName; | ||
if (varStack.top().dimensionsNum > 0) { | ||
waitingForDimensions = true; | ||
} | ||
|
||
} | ||
waitingForVar = !waitingForVar; | ||
} | ||
return RecursiveASTVisitor::TraverseDeclRefExpr(Ex); | ||
} | ||
|
||
bool TraverseIntegerLiteral(IntegerLiteral *IL) { | ||
|
||
if (isInPragma) { | ||
if (waitingForDimensions && curDimensionNum == varStack.top().dimensionsNum) { | ||
waitingForDimensions = false; | ||
curDimensionNum = 0; | ||
} | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
int val = IL -> getValue().getLimitedValue(); | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (waitingForDimensions) { | ||
if (varStack.size()) { | ||
varStack.top().dimensions.push_back(val); | ||
curDimensionNum++; | ||
} | ||
} else if (!waitingForVar) { // get rvalue | ||
varStack.top().rvalName = std::to_string(val); | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
waitingForVar = !waitingForVar; | ||
if (varStack.top().dimensionsNum > 0) { | ||
waitingForDimensions = true; | ||
} | ||
} | ||
} | ||
return RecursiveASTVisitor::TraverseIntegerLiteral(IL); | ||
} | ||
|
||
#ifdef LLVM_DEBUG | ||
// debug info | ||
#endif | ||
|
||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
private: | ||
/// Return current scope. | ||
Stmt *getScope() { | ||
for (auto I = mScopes.rbegin(), EI = mScopes.rend(); I != EI; ++I) | ||
if (isa<ForStmt>(*I) || isa<CompoundStmt>(*I)) | ||
return *I; | ||
return nullptr; | ||
} | ||
|
||
bool isInPragma = false; | ||
bool waitingForVar = true; | ||
bool waitingForDimensions = false; | ||
int curDimensionNum = 0; | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
std::vector<Stmt*> mScopes; | ||
|
||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
TransformationContext *mTfmCtx; | ||
const ASTImportInfo &mImportInfo; | ||
ClangGlobalInfoPass::RawInfo *mRawInfo; | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Rewriter &mRewriter; | ||
ASTContext &mContext; | ||
SourceManager &mSrcMgr; | ||
const LangOptions &mLangOpts; | ||
SmallVector<Stmt *, 1> mClauses; | ||
|
||
std::stack<vars> varStack; | ||
|
||
}; | ||
} | ||
|
||
bool ClangRemoveFirstPrivate::runOnFunction(Function &F) { | ||
auto *M = F.getParent(); | ||
|
||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
auto *DISub{findMetadata(&F)}; | ||
if (!DISub) | ||
return false; | ||
auto *CU{DISub->getUnit()}; | ||
if (isC(CU->getSourceLanguage()) && isCXX(CU->getSourceLanguage())) | ||
return false; | ||
auto &TfmInfo{getAnalysis<TransformationEnginePass>()}; | ||
auto *TfmCtx{TfmInfo ? dyn_cast_or_null<ClangTransformationContext>( | ||
TfmInfo->getContext(*CU)) | ||
: nullptr}; | ||
if (!TfmCtx || !TfmCtx->hasInstance()) { | ||
F.getContext().emitError( | ||
"cannot transform sources" | ||
": transformation context is not available for the '" + | ||
F.getName() + "' function"); | ||
return false; | ||
} | ||
|
||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
auto FuncDecl = TfmCtx->getDeclForMangledName(F.getName()); | ||
if (!FuncDecl) | ||
return false; | ||
|
||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ASTImportInfo ImportStub; | ||
const auto *ImportInfo = &ImportStub; | ||
if (auto *ImportPass = getAnalysisIfAvailable<ImmutableASTImportInfoPass>()) | ||
ImportInfo = &ImportPass->getImportInfo(); | ||
auto &GIP = getAnalysis<ClangGlobalInfoPass>(); | ||
|
||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
DeclVisitor Visitor(*TfmCtx, *ImportInfo, GIP.getRawInfo()); | ||
NikitaGorbov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Visitor.TraverseDecl(FuncDecl); | ||
return false; | ||
} | ||
|
||
void ClangRemoveFirstPrivate::getAnalysisUsage(AnalysisUsage &AU) const { | ||
AU.addRequired<TransformationEnginePass>(); | ||
AU.addRequired<ClangGlobalInfoPass>(); | ||
AU.setPreservesAll(); | ||
} | ||
|
||
FunctionPass *llvm::createClangRemoveFirstPrivate() { | ||
return new ClangRemoveFirstPrivate(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Нужно убрать изменения строк, которые не были затронуты (символы завершения строки).