Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,117 @@
//===-- MPIBugReporter.cpp - bug reporter -----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines prefabricated reports which are emitted in
/// case of MPI related bugs, detected by path-sensitive analysis.
///
//===----------------------------------------------------------------------===//
#include "MPIBugReporter.h"
#include "MPIChecker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
namespace clang {
namespace ento {
namespace mpi {
void MPIBugReporter::reportDoubleNonblocking(
const CallEvent &MPICallEvent, const ento::mpi::Request &Req,
const MemRegion *const RequestRegion,
const ExplodedNode *const ExplNode,
BugReporter &BReporter) const {
std::string ErrorText;
ErrorText = "Double nonblocking on request " +
RequestRegion->getDescriptiveName() + ". ";
auto Report = llvm::make_unique<BugReport>(*DoubleNonblockingBugType,
ErrorText, ExplNode);
Report->addRange(MPICallEvent.getSourceRange());
SourceRange Range = RequestRegion->sourceRange();
if (Range.isValid())
Report->addRange(Range);
Report->addVisitor(llvm::make_unique<RequestNodeVisitor>(
RequestRegion, "Request is previously used by nonblocking call here. "));
Report->markInteresting(RequestRegion);
BReporter.emitReport(std::move(Report));
}
void MPIBugReporter::reportMissingWait(
const ento::mpi::Request &Req, const MemRegion *const RequestRegion,
const ExplodedNode *const ExplNode,
BugReporter &BReporter) const {
std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
" has no matching wait. "};
auto Report =
llvm::make_unique<BugReport>(*MissingWaitBugType, ErrorText, ExplNode);
SourceRange Range = RequestRegion->sourceRange();
if (Range.isValid())
Report->addRange(Range);
Report->addVisitor(llvm::make_unique<RequestNodeVisitor>(
RequestRegion, "Request is previously used by nonblocking call here. "));
Report->markInteresting(RequestRegion);
BReporter.emitReport(std::move(Report));
}
void MPIBugReporter::reportUnmatchedWait(
const CallEvent &CE, const clang::ento::MemRegion *const RequestRegion,
const ExplodedNode *const ExplNode,
BugReporter &BReporter) const {
std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
" has no matching nonblocking call. "};
auto Report =
llvm::make_unique<BugReport>(*UnmatchedWaitBugType, ErrorText, ExplNode);
Report->addRange(CE.getSourceRange());
SourceRange Range = RequestRegion->sourceRange();
if (Range.isValid())
Report->addRange(Range);
BReporter.emitReport(std::move(Report));
}
std::shared_ptr<PathDiagnosticPiece>
MPIBugReporter::RequestNodeVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
BugReport &BR) {
if (IsNodeFound)
return nullptr;
const Request *const Req = N->getState()->get<RequestMap>(RequestRegion);
const Request *const PrevReq =
PrevN->getState()->get<RequestMap>(RequestRegion);
// Check if request was previously unused or in a different state.
if ((Req && !PrevReq) || (Req->CurrentState != PrevReq->CurrentState)) {
IsNodeFound = true;
ProgramPoint P = PrevN->getLocation();
PathDiagnosticLocation L =
PathDiagnosticLocation::create(P, BRC.getSourceManager());
return std::make_shared<PathDiagnosticEventPiece>(L, ErrorText);
}
return nullptr;
}
} // end of namespace: mpi
} // end of namespace: ento
} // end of namespace: clang

View File

@@ -0,0 +1,109 @@
//===-- MPIBugReporter.h - bug reporter -----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines prefabricated reports which are emitted in
/// case of MPI related bugs, detected by path-sensitive analysis.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIBUGREPORTER_H
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIBUGREPORTER_H
#include "MPITypes.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
namespace clang {
namespace ento {
namespace mpi {
class MPIBugReporter {
public:
MPIBugReporter(const CheckerBase &CB) {
UnmatchedWaitBugType.reset(new BugType(&CB, "Unmatched wait", MPIError));
DoubleNonblockingBugType.reset(
new BugType(&CB, "Double nonblocking", MPIError));
MissingWaitBugType.reset(new BugType(&CB, "Missing wait", MPIError));
}
/// Report duplicate request use by nonblocking calls without intermediate
/// wait.
///
/// \param MPICallEvent MPI call that caused the double nonblocking
/// \param Req request that was used by two nonblocking calls in sequence
/// \param RequestRegion memory region of the request
/// \param ExplNode node in the graph the bug appeared at
/// \param BReporter bug reporter for current context
void reportDoubleNonblocking(const CallEvent &MPICallEvent,
const Request &Req,
const MemRegion *const RequestRegion,
const ExplodedNode *const ExplNode,
BugReporter &BReporter) const;
/// Report a missing wait for a nonblocking call.
///
/// \param Req request that is not matched by a wait
/// \param RequestRegion memory region of the request
/// \param ExplNode node in the graph the bug appeared at
/// \param BReporter bug reporter for current context
void reportMissingWait(const Request &Req,
const MemRegion *const RequestRegion,
const ExplodedNode *const ExplNode,
BugReporter &BReporter) const;
/// Report a wait on a request that has not been used at all before.
///
/// \param CE wait call that uses the request
/// \param RequestRegion memory region of the request
/// \param ExplNode node in the graph the bug appeared at
/// \param BReporter bug reporter for current context
void reportUnmatchedWait(const CallEvent &CE,
const MemRegion *const RequestRegion,
const ExplodedNode *const ExplNode,
BugReporter &BReporter) const;
private:
const std::string MPIError = "MPI Error";
// path-sensitive bug types
std::unique_ptr<BugType> UnmatchedWaitBugType;
std::unique_ptr<BugType> MissingWaitBugType;
std::unique_ptr<BugType> DoubleNonblockingBugType;
/// Bug visitor class to find the node where the request region was previously
/// used in order to include it into the BugReport path.
class RequestNodeVisitor : public BugReporterVisitorImpl<RequestNodeVisitor> {
public:
RequestNodeVisitor(const MemRegion *const MemoryRegion,
const std::string &ErrText)
: RequestRegion(MemoryRegion), ErrorText(ErrText) {}
void Profile(llvm::FoldingSetNodeID &ID) const override {
static int X = 0;
ID.AddPointer(&X);
ID.AddPointer(RequestRegion);
}
std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
BugReport &BR) override;
private:
const MemRegion *const RequestRegion;
bool IsNodeFound = false;
std::string ErrorText;
};
};
} // end of namespace: mpi
} // end of namespace: ento
} // end of namespace: clang
#endif

View File

@@ -0,0 +1,193 @@
//===-- MPIChecker.cpp - Checker Entry Point Class --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the main class of MPI-Checker which serves as an entry
/// point. It is created once for each translation unit analysed.
/// The checker defines path-sensitive checks, to verify correct usage of the
/// MPI API.
///
//===----------------------------------------------------------------------===//
#include "MPIChecker.h"
#include "../ClangSACheckers.h"
namespace clang {
namespace ento {
namespace mpi {
void MPIChecker::checkDoubleNonblocking(const CallEvent &PreCallEvent,
CheckerContext &Ctx) const {
if (!FuncClassifier->isNonBlockingType(PreCallEvent.getCalleeIdentifier())) {
return;
}
const MemRegion *const MR =
PreCallEvent.getArgSVal(PreCallEvent.getNumArgs() - 1).getAsRegion();
if (!MR)
return;
const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);
// The region must be typed, in order to reason about it.
if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
return;
ProgramStateRef State = Ctx.getState();
const Request *const Req = State->get<RequestMap>(MR);
// double nonblocking detected
if (Req && Req->CurrentState == Request::State::Nonblocking) {
ExplodedNode *ErrorNode = Ctx.generateNonFatalErrorNode();
BReporter.reportDoubleNonblocking(PreCallEvent, *Req, MR, ErrorNode,
Ctx.getBugReporter());
Ctx.addTransition(ErrorNode->getState(), ErrorNode);
}
// no error
else {
State = State->set<RequestMap>(MR, Request::State::Nonblocking);
Ctx.addTransition(State);
}
}
void MPIChecker::checkUnmatchedWaits(const CallEvent &PreCallEvent,
CheckerContext &Ctx) const {
if (!FuncClassifier->isWaitType(PreCallEvent.getCalleeIdentifier()))
return;
const MemRegion *const MR = topRegionUsedByWait(PreCallEvent);
if (!MR)
return;
const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);
// The region must be typed, in order to reason about it.
if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
return;
llvm::SmallVector<const MemRegion *, 2> ReqRegions;
allRegionsUsedByWait(ReqRegions, MR, PreCallEvent, Ctx);
if (ReqRegions.empty())
return;
ProgramStateRef State = Ctx.getState();
static CheckerProgramPointTag Tag("MPI-Checker", "UnmatchedWait");
ExplodedNode *ErrorNode{nullptr};
// Check all request regions used by the wait function.
for (const auto &ReqRegion : ReqRegions) {
const Request *const Req = State->get<RequestMap>(ReqRegion);
State = State->set<RequestMap>(ReqRegion, Request::State::Wait);
if (!Req) {
if (!ErrorNode) {
ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag);
State = ErrorNode->getState();
}
// A wait has no matching nonblocking call.
BReporter.reportUnmatchedWait(PreCallEvent, ReqRegion, ErrorNode,
Ctx.getBugReporter());
}
}
if (!ErrorNode) {
Ctx.addTransition(State);
} else {
Ctx.addTransition(State, ErrorNode);
}
}
void MPIChecker::checkMissingWaits(SymbolReaper &SymReaper,
CheckerContext &Ctx) const {
if (!SymReaper.hasDeadSymbols())
return;
ProgramStateRef State = Ctx.getState();
const auto &Requests = State->get<RequestMap>();
if (Requests.isEmpty())
return;
static CheckerProgramPointTag Tag("MPI-Checker", "MissingWait");
ExplodedNode *ErrorNode{nullptr};
auto ReqMap = State->get<RequestMap>();
for (const auto &Req : ReqMap) {
if (!SymReaper.isLiveRegion(Req.first)) {
if (Req.second.CurrentState == Request::State::Nonblocking) {
if (!ErrorNode) {
ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag);
State = ErrorNode->getState();
}
BReporter.reportMissingWait(Req.second, Req.first, ErrorNode,
Ctx.getBugReporter());
}
State = State->remove<RequestMap>(Req.first);
}
}
// Transition to update the state regarding removed requests.
if (!ErrorNode) {
Ctx.addTransition(State);
} else {
Ctx.addTransition(State, ErrorNode);
}
}
const MemRegion *MPIChecker::topRegionUsedByWait(const CallEvent &CE) const {
if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) {
return CE.getArgSVal(0).getAsRegion();
} else if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
return CE.getArgSVal(1).getAsRegion();
} else {
return (const MemRegion *)nullptr;
}
}
void MPIChecker::allRegionsUsedByWait(
llvm::SmallVector<const MemRegion *, 2> &ReqRegions,
const MemRegion *const MR, const CallEvent &CE, CheckerContext &Ctx) const {
MemRegionManager *const RegionManager = MR->getMemRegionManager();
if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
const SubRegion *SuperRegion{nullptr};
if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {
SuperRegion = cast<SubRegion>(ER->getSuperRegion());
}
// A single request is passed to MPI_Waitall.
if (!SuperRegion) {
ReqRegions.push_back(MR);
return;
}
const auto &Size = Ctx.getStoreManager().getSizeInElements(
Ctx.getState(), SuperRegion,
CE.getArgExpr(1)->getType()->getPointeeType());
const llvm::APSInt &ArrSize = Size.getAs<nonloc::ConcreteInt>()->getValue();
for (size_t i = 0; i < ArrSize; ++i) {
const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i);
const ElementRegion *const ER = RegionManager->getElementRegion(
CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion,
Ctx.getASTContext());
ReqRegions.push_back(ER->getAs<MemRegion>());
}
} else if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) {
ReqRegions.push_back(MR);
}
}
} // end of namespace: mpi
} // end of namespace: ento
} // end of namespace: clang
// Registers the checker for static analysis.
void clang::ento::registerMPIChecker(CheckerManager &MGR) {
MGR.registerChecker<clang::ento::mpi::MPIChecker>();
}

View File

@@ -0,0 +1,105 @@
//===-- MPIChecker.h - Verify MPI API usage- --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the main class of MPI-Checker which serves as an entry
/// point. It is created once for each translation unit analysed.
/// The checker defines path-sensitive checks, to verify correct usage of the
/// MPI API.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPICHECKER_H
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPICHECKER_H
#include "MPIBugReporter.h"
#include "MPITypes.h"
#include "clang/StaticAnalyzer/Checkers/MPIFunctionClassifier.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
namespace clang {
namespace ento {
namespace mpi {
class MPIChecker : public Checker<check::PreCall, check::DeadSymbols> {
public:
MPIChecker() : BReporter(*this) {}
// path-sensitive callbacks
void checkPreCall(const CallEvent &CE, CheckerContext &Ctx) const {
dynamicInit(Ctx);
checkUnmatchedWaits(CE, Ctx);
checkDoubleNonblocking(CE, Ctx);
}
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &Ctx) const {
dynamicInit(Ctx);
checkMissingWaits(SymReaper, Ctx);
}
void dynamicInit(CheckerContext &Ctx) const {
if (FuncClassifier)
return;
const_cast<std::unique_ptr<MPIFunctionClassifier> &>(FuncClassifier)
.reset(new MPIFunctionClassifier{Ctx.getASTContext()});
}
/// Checks if a request is used by nonblocking calls multiple times
/// in sequence without intermediate wait. The check contains a guard,
/// in order to only inspect nonblocking functions.
///
/// \param PreCallEvent MPI call to verify
void checkDoubleNonblocking(const clang::ento::CallEvent &PreCallEvent,
clang::ento::CheckerContext &Ctx) const;
/// Checks if the request used by the wait function was not used at all
/// before. The check contains a guard, in order to only inspect wait
/// functions.
///
/// \param PreCallEvent MPI call to verify
void checkUnmatchedWaits(const clang::ento::CallEvent &PreCallEvent,
clang::ento::CheckerContext &Ctx) const;
/// Check if a nonblocking call is not matched by a wait.
/// If a memory region is not alive and the last function using the
/// request was a nonblocking call, this is rated as a missing wait.
void checkMissingWaits(clang::ento::SymbolReaper &SymReaper,
clang::ento::CheckerContext &Ctx) const;
private:
/// Collects all memory regions of a request(array) used by a wait
/// function. If the wait function uses a single request, this is a single
/// region. For wait functions using multiple requests, multiple regions
/// representing elements in the array are collected.
///
/// \param ReqRegions vector the regions get pushed into
/// \param MR top most region to iterate
/// \param CE MPI wait call using the request(s)
void allRegionsUsedByWait(
llvm::SmallVector<const clang::ento::MemRegion *, 2> &ReqRegions,
const clang::ento::MemRegion *const MR, const clang::ento::CallEvent &CE,
clang::ento::CheckerContext &Ctx) const;
/// Returns the memory region used by a wait function.
/// Distinguishes between MPI_Wait and MPI_Waitall.
///
/// \param CE MPI wait call
const clang::ento::MemRegion *
topRegionUsedByWait(const clang::ento::CallEvent &CE) const;
const std::unique_ptr<MPIFunctionClassifier> FuncClassifier;
MPIBugReporter BReporter;
};
} // end of namespace: mpi
} // end of namespace: ento
} // end of namespace: clang
#endif

View File

@@ -0,0 +1,284 @@
//===-- MPIFunctionClassifier.cpp - classifies MPI functions ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines functionality to identify and classify MPI functions.
///
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Checkers/MPIFunctionClassifier.h"
#include "llvm/ADT/STLExtras.h"
namespace clang {
namespace ento {
namespace mpi {
void MPIFunctionClassifier::identifierInit(ASTContext &ASTCtx) {
// Initialize function identifiers.
initPointToPointIdentifiers(ASTCtx);
initCollectiveIdentifiers(ASTCtx);
initAdditionalIdentifiers(ASTCtx);
}
void MPIFunctionClassifier::initPointToPointIdentifiers(ASTContext &ASTCtx) {
// Copy identifiers into the correct classification containers.
IdentInfo_MPI_Send = &ASTCtx.Idents.get("MPI_Send");
MPIPointToPointTypes.push_back(IdentInfo_MPI_Send);
MPIType.push_back(IdentInfo_MPI_Send);
assert(IdentInfo_MPI_Send);
IdentInfo_MPI_Isend = &ASTCtx.Idents.get("MPI_Isend");
MPIPointToPointTypes.push_back(IdentInfo_MPI_Isend);
MPINonBlockingTypes.push_back(IdentInfo_MPI_Isend);
MPIType.push_back(IdentInfo_MPI_Isend);
assert(IdentInfo_MPI_Isend);
IdentInfo_MPI_Ssend = &ASTCtx.Idents.get("MPI_Ssend");
MPIPointToPointTypes.push_back(IdentInfo_MPI_Ssend);
MPIType.push_back(IdentInfo_MPI_Ssend);
assert(IdentInfo_MPI_Ssend);
IdentInfo_MPI_Issend = &ASTCtx.Idents.get("MPI_Issend");
MPIPointToPointTypes.push_back(IdentInfo_MPI_Issend);
MPINonBlockingTypes.push_back(IdentInfo_MPI_Issend);
MPIType.push_back(IdentInfo_MPI_Issend);
assert(IdentInfo_MPI_Issend);
IdentInfo_MPI_Bsend = &ASTCtx.Idents.get("MPI_Bsend");
MPIPointToPointTypes.push_back(IdentInfo_MPI_Bsend);
MPIType.push_back(IdentInfo_MPI_Bsend);
assert(IdentInfo_MPI_Bsend);
IdentInfo_MPI_Ibsend = &ASTCtx.Idents.get("MPI_Ibsend");
MPIPointToPointTypes.push_back(IdentInfo_MPI_Ibsend);
MPINonBlockingTypes.push_back(IdentInfo_MPI_Ibsend);
MPIType.push_back(IdentInfo_MPI_Ibsend);
assert(IdentInfo_MPI_Ibsend);
IdentInfo_MPI_Rsend = &ASTCtx.Idents.get("MPI_Rsend");
MPIPointToPointTypes.push_back(IdentInfo_MPI_Rsend);
MPIType.push_back(IdentInfo_MPI_Rsend);
assert(IdentInfo_MPI_Rsend);
IdentInfo_MPI_Irsend = &ASTCtx.Idents.get("MPI_Irsend");
MPIPointToPointTypes.push_back(IdentInfo_MPI_Irsend);
MPIType.push_back(IdentInfo_MPI_Irsend);
assert(IdentInfo_MPI_Irsend);
IdentInfo_MPI_Recv = &ASTCtx.Idents.get("MPI_Recv");
MPIPointToPointTypes.push_back(IdentInfo_MPI_Recv);
MPIType.push_back(IdentInfo_MPI_Recv);
assert(IdentInfo_MPI_Recv);
IdentInfo_MPI_Irecv = &ASTCtx.Idents.get("MPI_Irecv");
MPIPointToPointTypes.push_back(IdentInfo_MPI_Irecv);
MPINonBlockingTypes.push_back(IdentInfo_MPI_Irecv);
MPIType.push_back(IdentInfo_MPI_Irecv);
assert(IdentInfo_MPI_Irecv);
}
void MPIFunctionClassifier::initCollectiveIdentifiers(ASTContext &ASTCtx) {
// Copy identifiers into the correct classification containers.
IdentInfo_MPI_Scatter = &ASTCtx.Idents.get("MPI_Scatter");
MPICollectiveTypes.push_back(IdentInfo_MPI_Scatter);
MPIPointToCollTypes.push_back(IdentInfo_MPI_Scatter);
MPIType.push_back(IdentInfo_MPI_Scatter);
assert(IdentInfo_MPI_Scatter);
IdentInfo_MPI_Iscatter = &ASTCtx.Idents.get("MPI_Iscatter");
MPICollectiveTypes.push_back(IdentInfo_MPI_Iscatter);
MPIPointToCollTypes.push_back(IdentInfo_MPI_Iscatter);
MPINonBlockingTypes.push_back(IdentInfo_MPI_Iscatter);
MPIType.push_back(IdentInfo_MPI_Iscatter);
assert(IdentInfo_MPI_Iscatter);
IdentInfo_MPI_Gather = &ASTCtx.Idents.get("MPI_Gather");
MPICollectiveTypes.push_back(IdentInfo_MPI_Gather);
MPICollToPointTypes.push_back(IdentInfo_MPI_Gather);
MPIType.push_back(IdentInfo_MPI_Gather);
assert(IdentInfo_MPI_Gather);
IdentInfo_MPI_Igather = &ASTCtx.Idents.get("MPI_Igather");
MPICollectiveTypes.push_back(IdentInfo_MPI_Igather);
MPICollToPointTypes.push_back(IdentInfo_MPI_Igather);
MPINonBlockingTypes.push_back(IdentInfo_MPI_Igather);
MPIType.push_back(IdentInfo_MPI_Igather);
assert(IdentInfo_MPI_Igather);
IdentInfo_MPI_Allgather = &ASTCtx.Idents.get("MPI_Allgather");
MPICollectiveTypes.push_back(IdentInfo_MPI_Allgather);
MPICollToCollTypes.push_back(IdentInfo_MPI_Allgather);
MPIType.push_back(IdentInfo_MPI_Allgather);
assert(IdentInfo_MPI_Allgather);
IdentInfo_MPI_Iallgather = &ASTCtx.Idents.get("MPI_Iallgather");
MPICollectiveTypes.push_back(IdentInfo_MPI_Iallgather);
MPICollToCollTypes.push_back(IdentInfo_MPI_Iallgather);
MPINonBlockingTypes.push_back(IdentInfo_MPI_Iallgather);
MPIType.push_back(IdentInfo_MPI_Iallgather);
assert(IdentInfo_MPI_Iallgather);
IdentInfo_MPI_Bcast = &ASTCtx.Idents.get("MPI_Bcast");
MPICollectiveTypes.push_back(IdentInfo_MPI_Bcast);
MPIPointToCollTypes.push_back(IdentInfo_MPI_Bcast);
MPIType.push_back(IdentInfo_MPI_Bcast);
assert(IdentInfo_MPI_Bcast);
IdentInfo_MPI_Ibcast = &ASTCtx.Idents.get("MPI_Ibcast");
MPICollectiveTypes.push_back(IdentInfo_MPI_Ibcast);
MPIPointToCollTypes.push_back(IdentInfo_MPI_Ibcast);
MPINonBlockingTypes.push_back(IdentInfo_MPI_Ibcast);
MPIType.push_back(IdentInfo_MPI_Ibcast);
assert(IdentInfo_MPI_Ibcast);
IdentInfo_MPI_Reduce = &ASTCtx.Idents.get("MPI_Reduce");
MPICollectiveTypes.push_back(IdentInfo_MPI_Reduce);
MPICollToPointTypes.push_back(IdentInfo_MPI_Reduce);
MPIType.push_back(IdentInfo_MPI_Reduce);
assert(IdentInfo_MPI_Reduce);
IdentInfo_MPI_Ireduce = &ASTCtx.Idents.get("MPI_Ireduce");
MPICollectiveTypes.push_back(IdentInfo_MPI_Ireduce);
MPICollToPointTypes.push_back(IdentInfo_MPI_Ireduce);
MPINonBlockingTypes.push_back(IdentInfo_MPI_Ireduce);
MPIType.push_back(IdentInfo_MPI_Ireduce);
assert(IdentInfo_MPI_Ireduce);
IdentInfo_MPI_Allreduce = &ASTCtx.Idents.get("MPI_Allreduce");
MPICollectiveTypes.push_back(IdentInfo_MPI_Allreduce);
MPICollToCollTypes.push_back(IdentInfo_MPI_Allreduce);
MPIType.push_back(IdentInfo_MPI_Allreduce);
assert(IdentInfo_MPI_Allreduce);
IdentInfo_MPI_Iallreduce = &ASTCtx.Idents.get("MPI_Iallreduce");
MPICollectiveTypes.push_back(IdentInfo_MPI_Iallreduce);
MPICollToCollTypes.push_back(IdentInfo_MPI_Iallreduce);
MPINonBlockingTypes.push_back(IdentInfo_MPI_Iallreduce);
MPIType.push_back(IdentInfo_MPI_Iallreduce);
assert(IdentInfo_MPI_Iallreduce);
IdentInfo_MPI_Alltoall = &ASTCtx.Idents.get("MPI_Alltoall");
MPICollectiveTypes.push_back(IdentInfo_MPI_Alltoall);
MPICollToCollTypes.push_back(IdentInfo_MPI_Alltoall);
MPIType.push_back(IdentInfo_MPI_Alltoall);
assert(IdentInfo_MPI_Alltoall);
IdentInfo_MPI_Ialltoall = &ASTCtx.Idents.get("MPI_Ialltoall");
MPICollectiveTypes.push_back(IdentInfo_MPI_Ialltoall);
MPICollToCollTypes.push_back(IdentInfo_MPI_Ialltoall);
MPINonBlockingTypes.push_back(IdentInfo_MPI_Ialltoall);
MPIType.push_back(IdentInfo_MPI_Ialltoall);
assert(IdentInfo_MPI_Ialltoall);
}
void MPIFunctionClassifier::initAdditionalIdentifiers(ASTContext &ASTCtx) {
IdentInfo_MPI_Comm_rank = &ASTCtx.Idents.get("MPI_Comm_rank");
MPIType.push_back(IdentInfo_MPI_Comm_rank);
assert(IdentInfo_MPI_Comm_rank);
IdentInfo_MPI_Comm_size = &ASTCtx.Idents.get("MPI_Comm_size");
MPIType.push_back(IdentInfo_MPI_Comm_size);
assert(IdentInfo_MPI_Comm_size);
IdentInfo_MPI_Wait = &ASTCtx.Idents.get("MPI_Wait");
MPIType.push_back(IdentInfo_MPI_Wait);
assert(IdentInfo_MPI_Wait);
IdentInfo_MPI_Waitall = &ASTCtx.Idents.get("MPI_Waitall");
MPIType.push_back(IdentInfo_MPI_Waitall);
assert(IdentInfo_MPI_Waitall);
IdentInfo_MPI_Barrier = &ASTCtx.Idents.get("MPI_Barrier");
MPICollectiveTypes.push_back(IdentInfo_MPI_Barrier);
MPIType.push_back(IdentInfo_MPI_Barrier);
assert(IdentInfo_MPI_Barrier);
}
// general identifiers
bool MPIFunctionClassifier::isMPIType(const IdentifierInfo *IdentInfo) const {
return llvm::is_contained(MPIType, IdentInfo);
}
bool MPIFunctionClassifier::isNonBlockingType(
const IdentifierInfo *IdentInfo) const {
return llvm::is_contained(MPINonBlockingTypes, IdentInfo);
}
// point-to-point identifiers
bool MPIFunctionClassifier::isPointToPointType(
const IdentifierInfo *IdentInfo) const {
return llvm::is_contained(MPIPointToPointTypes, IdentInfo);
}
// collective identifiers
bool MPIFunctionClassifier::isCollectiveType(
const IdentifierInfo *IdentInfo) const {
return llvm::is_contained(MPICollectiveTypes, IdentInfo);
}
bool MPIFunctionClassifier::isCollToColl(
const IdentifierInfo *IdentInfo) const {
return llvm::is_contained(MPICollToCollTypes, IdentInfo);
}
bool MPIFunctionClassifier::isScatterType(
const IdentifierInfo *IdentInfo) const {
return IdentInfo == IdentInfo_MPI_Scatter ||
IdentInfo == IdentInfo_MPI_Iscatter;
}
bool MPIFunctionClassifier::isGatherType(
const IdentifierInfo *IdentInfo) const {
return IdentInfo == IdentInfo_MPI_Gather ||
IdentInfo == IdentInfo_MPI_Igather ||
IdentInfo == IdentInfo_MPI_Allgather ||
IdentInfo == IdentInfo_MPI_Iallgather;
}
bool MPIFunctionClassifier::isAllgatherType(
const IdentifierInfo *IdentInfo) const {
return IdentInfo == IdentInfo_MPI_Allgather ||
IdentInfo == IdentInfo_MPI_Iallgather;
}
bool MPIFunctionClassifier::isAlltoallType(
const IdentifierInfo *IdentInfo) const {
return IdentInfo == IdentInfo_MPI_Alltoall ||
IdentInfo == IdentInfo_MPI_Ialltoall;
}
bool MPIFunctionClassifier::isBcastType(const IdentifierInfo *IdentInfo) const {
return IdentInfo == IdentInfo_MPI_Bcast || IdentInfo == IdentInfo_MPI_Ibcast;
}
bool MPIFunctionClassifier::isReduceType(
const IdentifierInfo *IdentInfo) const {
return IdentInfo == IdentInfo_MPI_Reduce ||
IdentInfo == IdentInfo_MPI_Ireduce ||
IdentInfo == IdentInfo_MPI_Allreduce ||
IdentInfo == IdentInfo_MPI_Iallreduce;
}
// additional identifiers
bool MPIFunctionClassifier::isMPI_Wait(const IdentifierInfo *IdentInfo) const {
return IdentInfo == IdentInfo_MPI_Wait;
}
bool MPIFunctionClassifier::isMPI_Waitall(
const IdentifierInfo *IdentInfo) const {
return IdentInfo == IdentInfo_MPI_Waitall;
}
bool MPIFunctionClassifier::isWaitType(const IdentifierInfo *IdentInfo) const {
return IdentInfo == IdentInfo_MPI_Wait || IdentInfo == IdentInfo_MPI_Waitall;
}
} // end of namespace: mpi
} // end of namespace: ento
} // end of namespace: clang

View File

@@ -0,0 +1,67 @@
//===-- MPITypes.h - Functionality to model MPI concepts --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file provides definitions to model concepts of MPI. The mpi::Request
/// class defines a wrapper class, in order to make MPI requests trackable for
/// path-sensitive analysis.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPITYPES_H
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPITYPES_H
#include "clang/StaticAnalyzer/Checkers/MPIFunctionClassifier.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "llvm/ADT/SmallSet.h"
namespace clang {
namespace ento {
namespace mpi {
class Request {
public:
enum State : unsigned char { Nonblocking, Wait };
Request(State S) : CurrentState{S} {}
void Profile(llvm::FoldingSetNodeID &Id) const {
Id.AddInteger(CurrentState);
}
bool operator==(const Request &ToCompare) const {
return CurrentState == ToCompare.CurrentState;
}
const State CurrentState;
};
// The RequestMap stores MPI requests which are identified by their memory
// region. Requests are used in MPI to complete nonblocking operations with wait
// operations. A custom map implementation is used, in order to make it
// available in an arbitrary amount of translation units.
struct RequestMap {};
typedef llvm::ImmutableMap<const clang::ento::MemRegion *,
clang::ento::mpi::Request>
RequestMapImpl;
} // end of namespace: mpi
template <>
struct ProgramStateTrait<mpi::RequestMap>
: public ProgramStatePartialTrait<mpi::RequestMapImpl> {
static void *GDMIndex() {
static int index = 0;
return &index;
}
};
} // end of namespace: ento
} // end of namespace: clang
#endif