/** * Check if two calls are a send/recv pair. * * @param sendCall * @param recvCall * * @return if they are send/recv pair */ bool MPICheckerAST::isSendRecvPair(const MPICall &sendCall, const MPICall &recvCall) const { if (!funcClassifier_.isSendType(sendCall)) return false; if (!funcClassifier_.isRecvType(recvCall)) return false; if (!areDatatypesEqual(sendCall, recvCall)) return false; // compare count, tag for (const size_t idx : {MPIPointToPoint::kCount, MPIPointToPoint::kTag}) { if (!sendCall.arguments()[idx].isEqual(recvCall.arguments()[idx])) { return false; } } // compare ranks const auto &rankArgSend = sendCall.arguments()[MPIPointToPoint::kRank]; const auto &rankArgRecv = recvCall.arguments()[MPIPointToPoint::kRank]; if (rankArgSend.typeSequence().size() != rankArgRecv.typeSequence().size()) return false; // build sequences without last operator(skip first element) std::vector<ArgumentVisitor::ComponentType> seq1, seq2; std::vector<std::string> val1, val2; bool containsSubtraction{false}; for (size_t i = 1; i < rankArgSend.typeSequence().size(); ++i) { seq1.push_back(rankArgSend.typeSequence()[i]); val1.push_back(rankArgSend.valueSequence()[i]); seq2.push_back(rankArgRecv.typeSequence()[i]); val2.push_back(rankArgRecv.valueSequence()[i]); if (rankArgSend.valueSequence()[i] == "-") containsSubtraction = true; if (rankArgRecv.valueSequence()[i] == "-") containsSubtraction = true; } if (containsSubtraction) { // check ordered if (seq1 != seq2 || val1 != val2) return false; } else { // check permutation if ((!cont::isPermutation(seq1, seq2)) || (!cont::isPermutation(val1, val2))) { return false; } } // last (value|var|function) must be identical if (val1.back() != val2.back()) return false; // last operator must be inverse if (!rankArgSend.isLastOperatorInverse(rankArgRecv)) return false; return true; }
/** * Checks if mpi-datatypes for 2 different point to point calls are equal. * * @param sendCall * @param recvCall * * @return equality */ bool MPICheckerAST::areDatatypesEqual(const MPICall &sendCall, const MPICall &recvCall) const { // compare mpi datatype llvm::StringRef sendDataType = util::sourceRangeAsStringRef( sendCall.arguments()[MPIPointToPoint::kDatatype] .stmt_->getSourceRange(), analysisManager_); llvm::StringRef recvDataType = util::sourceRangeAsStringRef( recvCall.arguments()[MPIPointToPoint::kDatatype] .stmt_->getSourceRange(), analysisManager_); return sendDataType == recvDataType; }
/** * Checks if buffer type and specified mpi datatype matches. * * @param mpiCall call to check type correspondence for */ void MPICheckerAST::checkBufferTypeMatch(const MPICall &mpiCall) const { // one pair consists of {bufferIdx, mpiDatatypeIdx} IndexPairs indexPairs = bufferDataTypeIndices(mpiCall); // for every buffer mpi-data pair in function // check if their types match for (const auto &idxPair : indexPairs) { const VarDecl *bufferArg = mpiCall.arguments()[idxPair.first].vars().front(); // collect buffer type information const mpi::TypeVisitor typeVisitor{bufferArg->getType()}; // get mpi datatype as string auto mpiDatatype = mpiCall.arguments()[idxPair.second].stmt_; StringRef mpiDatatypeString{util::sourceRangeAsStringRef( mpiDatatype->getSourceRange(), analysisManager_)}; selectTypeMatcher(typeVisitor, mpiCall, mpiDatatypeString, idxPair); } }
/** * Check if invalid argument types are used in a mpi call. * This check looks at indices where only integer values are valid. * (count, rank, tag) Any non integer type usage is reported. * * @param mpiCall to check the arguments for */ void MPICheckerAST::checkForInvalidArgs(const MPICall &mpiCall) const { std::vector<size_t> indicesToCheck = integerIndices(mpiCall); if (!indicesToCheck.size()) return; // iterate indices which should not have integer arguments for (const size_t idx : indicesToCheck) { // check for invalid variable types const auto &arg = mpiCall.arguments()[idx]; const auto &vars = arg.vars(); for (const auto &var : vars) { const mpi::TypeVisitor typeVisitor{var->getType()}; if (!typeVisitor.builtinType() || !typeVisitor.builtinType()->isIntegerType()) { bugReporter_.reportInvalidArgumentType( mpiCall.callExpr(), idx, var->getSourceRange(), "Variable"); } } // check for float literals if (arg.floatingLiterals().size()) { bugReporter_.reportInvalidArgumentType( mpiCall.callExpr(), idx, arg.floatingLiterals().front()->getSourceRange(), "Literal"); } // check for invalid return types from functions const auto &functions = arg.functions(); for (const auto &function : functions) { const mpi::TypeVisitor typeVisitor{function->getReturnType()}; if (!typeVisitor.builtinType() || !typeVisitor.builtinType()->isIntegerType()) { bugReporter_.reportInvalidArgumentType( mpiCall.callExpr(), idx, function->getSourceRange(), "Return value"); } } } }