diff --git a/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp b/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp index 277b3ed2e1056..5fc27dc3ed51b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp @@ -174,6 +174,43 @@ void MPIFunctionClassifier::initCollectiveIdentifiers(ASTContext &ASTCtx) { MPINonBlockingTypes.push_back(IdentInfo_MPI_Ialltoall); MPIType.push_back(IdentInfo_MPI_Ialltoall); assert(IdentInfo_MPI_Ialltoall); + + auto AddCollective = [&](StringRef Name) { + IdentifierInfo *II = &ASTCtx.Idents.get(Name); + MPICollectiveTypes.push_back(II); + MPIType.push_back(II); + return II; + }; + auto AddNonBlockingCollective = [&](StringRef Name) { + MPINonBlockingTypes.push_back(AddCollective(Name)); + }; + + // Vector ("v"/"w") variants of the collectives above. + AddCollective("MPI_Scatterv"); + AddNonBlockingCollective("MPI_Iscatterv"); + AddCollective("MPI_Gatherv"); + AddNonBlockingCollective("MPI_Igatherv"); + AddCollective("MPI_Allgatherv"); + AddNonBlockingCollective("MPI_Iallgatherv"); + AddCollective("MPI_Alltoallv"); + AddNonBlockingCollective("MPI_Ialltoallv"); + AddCollective("MPI_Alltoallw"); + AddNonBlockingCollective("MPI_Ialltoallw"); + + // Nonblocking barrier. + AddNonBlockingCollective("MPI_Ibarrier"); + + // Prefix reductions (scans). + AddCollective("MPI_Scan"); + AddNonBlockingCollective("MPI_Iscan"); + AddCollective("MPI_Exscan"); + AddNonBlockingCollective("MPI_Iexscan"); + + // Reduce-scatter family. + AddCollective("MPI_Reduce_scatter"); + AddNonBlockingCollective("MPI_Ireduce_scatter"); + AddCollective("MPI_Reduce_scatter_block"); + AddNonBlockingCollective("MPI_Ireduce_scatter_block"); } void MPIFunctionClassifier::initAdditionalIdentifiers(ASTContext &ASTCtx) { diff --git a/clang/test/Analysis/MPIMock.h b/clang/test/Analysis/MPIMock.h index 01d2d42fc58a3..f3bc0676d132b 100644 --- a/clang/test/Analysis/MPIMock.h +++ b/clang/test/Analysis/MPIMock.h @@ -37,6 +37,7 @@ namespace std { template struct complex { T real; T imag; }; } #define MPI_COMM_WORLD 0 #define MPI_STATUS_IGNORE 0 #define MPI_STATUSES_IGNORE 0 +#define MPI_REQUEST_NULL 0 #define MPI_SUM 0 // mock functions @@ -53,3 +54,9 @@ int MPI_Reduce(const void *, void *, int, MPI_Datatype, MPI_Op, int, MPI_Comm); int MPI_Ireduce(const void *, void *, int, MPI_Datatype, MPI_Op, int, MPI_Comm, MPI_Request *); int MPI_Bcast(void *, int count, MPI_Datatype, int, MPI_Comm); +int MPI_Iscatterv(const void *, const int[], const int[], MPI_Datatype, void *, + int, MPI_Datatype, int, MPI_Comm, MPI_Request *); +int MPI_Iscan(const void *, void *, int, MPI_Datatype, MPI_Op, MPI_Comm, + MPI_Request *); +int MPI_Ireduce_scatter(const void *, void *, const int[], MPI_Datatype, + MPI_Op, MPI_Comm, MPI_Request *); diff --git a/clang/test/Analysis/mpichecker.cpp b/clang/test/Analysis/mpichecker.cpp index f7644520ebcf5..f2fd6c0951a2f 100644 --- a/clang/test/Analysis/mpichecker.cpp +++ b/clang/test/Analysis/mpichecker.cpp @@ -48,6 +48,46 @@ void matchedWait3() { } } // no error +void matchedWaitIscatterv() { + double buf = 0; + MPI_Request req = MPI_REQUEST_NULL; + MPI_Iscatterv(NULL, NULL, NULL, MPI_DATATYPE_NULL, &buf, 0, MPI_DATATYPE_NULL, + 0, MPI_COMM_WORLD, &req); + MPI_Wait(&req, MPI_STATUS_IGNORE); +} // no error: this used to report a FP before GH208107. + +void missingWaitIscatterv() { + double buf = 0; + MPI_Request req = MPI_REQUEST_NULL; + MPI_Iscatterv(NULL, NULL, NULL, MPI_DATATYPE_NULL, &buf, 0, MPI_DATATYPE_NULL, + 0, MPI_COMM_WORLD, &req); +} // expected-warning {{Request 'req' has no matching wait.}} + +void doubleNonblockingIscatterv() { + double buf = 0; + MPI_Request req = MPI_REQUEST_NULL; + MPI_Iscatterv(NULL, NULL, NULL, MPI_DATATYPE_NULL, &buf, 0, MPI_DATATYPE_NULL, + 0, MPI_COMM_WORLD, &req); + // expected-warning@+1 {{Double nonblocking on request 'req'.}} + MPI_Iscatterv(NULL, NULL, NULL, MPI_DATATYPE_NULL, &buf, 0, MPI_DATATYPE_NULL, + 0, MPI_COMM_WORLD, &req); + MPI_Wait(&req, MPI_STATUS_IGNORE); +} + +void matchedWaitIscan() { + double buf = 0; + MPI_Request req = MPI_REQUEST_NULL; + MPI_Iscan(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD, &req); + MPI_Wait(&req, MPI_STATUS_IGNORE); +} // no error + +void missingWaitIreduceScatter() { + double buf = 0; + MPI_Request req = MPI_REQUEST_NULL; + MPI_Ireduce_scatter(MPI_IN_PLACE, &buf, NULL, MPI_DOUBLE, MPI_SUM, + MPI_COMM_WORLD, &req); +} // expected-warning {{Request 'req' has no matching wait.}} + void missingWait1() { // Check missing wait for dead region. double buf = 0; MPI_Request sendReq1;