Skip to content

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

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1759c61
resolve merge conflict
NikitaGorbov Feb 24, 2022
bfd9a01
try to make a new pass: edit passes.h
NikitaGorbov Oct 20, 2021
1d9d69d
add pragma 'removefirstprivate'
NikitaGorbov Oct 29, 2021
1a63251
remove-firstprivate pass
NikitaGorbov Nov 11, 2021
6e9f702
remove unused code
NikitaGorbov Nov 11, 2021
945641d
add array initialization
NikitaGorbov Nov 25, 2021
34fb122
improvements
NikitaGorbov Dec 3, 2021
338cdb3
multidimensional array initialization and improvements
NikitaGorbov Dec 9, 2021
c50822d
add auto size determination for arrays
NikitaGorbov Dec 17, 2021
7386e89
add pointers initialization
NikitaGorbov Dec 22, 2021
522e71c
removefirstprivate: wrong counter initialization fix
NikitaGorbov Dec 23, 2021
1114bfe
fix incorrect dimension determination in some cases
NikitaGorbov Feb 24, 2022
1c44b9f
Rename pass, change pass syntax, add some improvements
NikitaGorbov Mar 16, 2022
906f162
better formating
NikitaGorbov Mar 16, 2022
5d8c0c4
rename variables, change some var declarations
NikitaGorbov Mar 18, 2022
05e69bf
remove some vars, change some types
NikitaGorbov Mar 22, 2022
24b8cae
add checks and warnings
NikitaGorbov Mar 25, 2022
67e4ca4
add error_not_var, fix wrong conditions for warning printing, change …
NikitaGorbov Mar 31, 2022
090c25d
clear redundant code
NikitaGorbov Mar 31, 2022
a543fc0
fix warning messages
NikitaGorbov Apr 8, 2022
43c9f2f
exit if incorrect pragma parameter found
NikitaGorbov Apr 13, 2022
19f6aea
add error flag
NikitaGorbov Apr 13, 2022
8d89107
change initialization order
NikitaGorbov Apr 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/tsar/Support/Directives.td
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ def AssertNoMacro : Clause<"nomacro", Assert>;
def RegionName : Clause<"name", Region,
[LParen, PPIdentifier, ZeroOrMore<[Comma, PPIdentifier]>, RParen]>;

def RemoveFirstPrivate : Clause<"removefirstprivate", Transform,
[LParen, Identifier, Equal, OneOf<[Identifier, NumericConstant]>, ZeroOrMore<[NumericConstant]>, ZeroOrMore<[Comma, Identifier, Equal, OneOf<[Identifier, NumericConstant]>, ZeroOrMore<[NumericConstant]>]>, RParen]>;

def ReplaceMetadata : Clause<"replace", Metadata,
[LParen,
Identifier, LParen,
Expand Down
9 changes: 8 additions & 1 deletion include/tsar/Transform/Clang/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ llvm::ModulePass * createClangRenameLocalPass();
/// Initializes a pass to perform source-level object renaming.
void initializeClangRenameLocalPassPass(PassRegistry &Registry);

/// Creates a pass to perform remove-firstprivate.
FunctionPass * createClangRemoveFirstPrivate();

/// Initializes a pass to perform remove-firstprivate.
void initializeClangRemoveFirstPrivatePass(PassRegistry &Registry);


/// Creates a pass to perform elimination of dead declarations.
FunctionPass * createClangDeadDeclsElimination();

Expand Down Expand Up @@ -115,4 +122,4 @@ void initializeClangLoopReversePass(PassRegistry &Registry);
/// Create a pass to reverse loop.
ModulePass *createClangLoopReverse();
}
#endif//TSAR_CLANG_TRANSFORM_PASSES_H
#endif//TSAR_CLANG_TRANSFORM_PASSES_H
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нужно убрать изменения строк, которые не были затронуты (символы завершения строки).

2 changes: 1 addition & 1 deletion lib/Transform/Clang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ set(TRANSFORM_SOURCES Passes.cpp ExprPropagation.cpp Inline.cpp RenameLocal.cpp
DeadDeclsElimination.cpp Format.cpp OpenMPAutoPar.cpp DVMHWriter.cpp
SharedMemoryAutoPar.cpp DVMHDirecitves.cpp DVMHSMAutoPar.cpp
DVMHDataTransferIPO.cpp StructureReplacement.cpp LoopInterchange.cpp
LoopReversal.cpp)
LoopReversal.cpp RemoveFirstPrivate.cpp)

if(MSVC_IDE)
file(GLOB_RECURSE TRANSFORM_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
Expand Down
1 change: 1 addition & 0 deletions lib/Transform/Clang/Passes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ void llvm::initializeClangTransform(PassRegistry &Registry) {
initializeDVMHDataTransferIPOPassPass(Registry);
initializeClangLoopInterchangePass(Registry);
initializeClangLoopReversePass(Registry);
initializeClangRemoveFirstPrivatePass(Registry);
}
349 changes: 349 additions & 0 deletions lib/Transform/Clang/RemoveFirstPrivate.cpp
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
//
// 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
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()) {}

bool TraverseStmt(Stmt *S) {
if (!S)
return true;

bool ast = false;
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Эти строки скорее всего маленькие, лучше использовать llvm::SmallString<...>, чтобы избежать лишних выделений памяти в куче. Например, llvm::SmallString<64> выделт строку на стеке длиной 64 символа, если не хватит, то неявно превратится в обычный string.

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;
} else {
varStack.pop();
continue; // dimensions ar mandatory for arrays, skip
} // initialization if no dimensions found
}
forBody = std::string();
indeces = std::string();
lval = varStack.top().lvalName;
rval = varStack.top().rvalName;
txtStr = std::string();
for (std::vector<int>::iterator it = varStack.top().dimensions.begin();
it != varStack.top().dimensions.end();
it ++) {
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";
}
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())}) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А что будет, если там не переменная, а что-то другое. Имя функции, структуры, typedef - это все тоже декларации. Должны быть проверки на корректность задания директив и соответствующие диагностические сообщения. Если директива некорректна, то это ошибка, если корректна, но преобразование по каким-то причинам не возможно, то это предупреждение.

varName = Var -> getName();
}
if (waitingForVar) { // get lvalue
ValueDecl *vd = Ex -> getDecl();
QualType qt = vd -> getType();
vars tmp;

tmp.lvalName = varName;
varStack.push(tmp);
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;
}
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;
}
int val = IL -> getValue().getLimitedValue();
if (waitingForDimensions) {
if (varStack.size()) {
varStack.top().dimensions.push_back(val);
curDimensionNum++;
}
} else if (!waitingForVar) { // get rvalue
varStack.top().rvalName = std::to_string(val);
waitingForVar = !waitingForVar;
if (varStack.top().dimensionsNum > 0) {
waitingForDimensions = true;
}
}
}
return RecursiveASTVisitor::TraverseIntegerLiteral(IL);
}

#ifdef LLVM_DEBUG
// debug info
#endif

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;

std::vector<Stmt*> mScopes;

TransformationContext *mTfmCtx;
const ASTImportInfo &mImportInfo;
ClangGlobalInfoPass::RawInfo *mRawInfo;
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();

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;
}

auto FuncDecl = TfmCtx->getDeclForMangledName(F.getName());
if (!FuncDecl)
return false;

ASTImportInfo ImportStub;
const auto *ImportInfo = &ImportStub;
if (auto *ImportPass = getAnalysisIfAvailable<ImmutableASTImportInfoPass>())
ImportInfo = &ImportPass->getImportInfo();
auto &GIP = getAnalysis<ClangGlobalInfoPass>();

DeclVisitor Visitor(*TfmCtx, *ImportInfo, GIP.getRawInfo());
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();
}