/** * Select apprioriate function to match the buffer type against * the specified mpi datatype. * * @param typeVisitor contains information about the buffer * @param mpiCall call whose arguments are observed * @param mpiDatatypeString * @param idxPair bufferIdx, mpiDatatypeIdx */ void MPICheckerAST::selectTypeMatcher( const mpi::TypeVisitor &typeVisitor, const MPICall &mpiCall, const StringRef mpiDatatypeString, const std::pair<size_t, size_t> &idxPair) const { const clang::BuiltinType *builtinType = typeVisitor.builtinType(); bool isTypeMatching{true}; // check for exact width types (e.g. int16_t, uint32_t) if (typeVisitor.isTypedefType()) { isTypeMatching = matchExactWidthType(typeVisitor, mpiDatatypeString); } // check for complex-floating types (e.g. float _Complex) else if (typeVisitor.isComplexType()) { isTypeMatching = matchComplexType(typeVisitor, mpiDatatypeString); } // check for basic builtin types (e.g. int, char) else if (!builtinType) { return; // if no builtin type cancel checking } else if (builtinType->isBooleanType()) { isTypeMatching = matchBoolType(typeVisitor, mpiDatatypeString); } else if (builtinType->isAnyCharacterType()) { isTypeMatching = matchCharType(typeVisitor, mpiDatatypeString); } else if (builtinType->isSignedInteger()) { isTypeMatching = matchSignedType(typeVisitor, mpiDatatypeString); } else if (builtinType->isUnsignedIntegerType()) { isTypeMatching = matchUnsignedType(typeVisitor, mpiDatatypeString); } else if (builtinType->isFloatingType()) { isTypeMatching = matchFloatType(typeVisitor, mpiDatatypeString); } if (!isTypeMatching) bugReporter_.reportTypeMismatch(mpiCall.callExpr(), idxPair, typeVisitor.qualType_, mpiDatatypeString); }
/** * Returns index pairs for each buffer, datatype pair. * * @param mpiCall * * @return index pairs */ MPICheckerAST::IndexPairs MPICheckerAST::bufferDataTypeIndices( const MPICall &mpiCall) const { IndexPairs indexPairs; if (funcClassifier_.isPointToPointType(mpiCall)) { indexPairs.push_back( {MPIPointToPoint::kBuf, MPIPointToPoint::kDatatype}); } else if (funcClassifier_.isCollectiveType(mpiCall)) { if (funcClassifier_.isReduceType(mpiCall)) { // only check buffer type if not inplace if (util::sourceRangeAsStringRef( mpiCall.callExpr()->getArg(0)->getSourceRange(), analysisManager_) != "MPI_IN_PLACE") { indexPairs.push_back({0, 3}); } indexPairs.push_back({1, 3}); } else if (funcClassifier_.isScatterType(mpiCall) || funcClassifier_.isGatherType(mpiCall) || funcClassifier_.isAlltoallType(mpiCall)) { indexPairs.push_back({0, 2}); indexPairs.push_back({3, 5}); } else if (funcClassifier_.isBcastType(mpiCall)) { indexPairs.push_back({0, 2}); } } return indexPairs; }
/** * 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.callExpr() ->getArg(MPIPointToPoint::kDatatype) ->getSourceRange(), analysisManager_); llvm::StringRef recvDataType = util::sourceRangeAsStringRef(recvCall.callExpr() ->getArg(MPIPointToPoint::kDatatype) ->getSourceRange(), analysisManager_); return sendDataType == recvDataType; }
/** * 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"); } } } }
/** * Check if there is a redundant call to the call passed. * * @param callToCheck */ void MPICheckerAST::checkForRedundantCall(const MPICall &callToCheck, const MPIRankCase &rankCase) const { for (const MPICall &comparedCall : rankCase.mpiCalls()) { if (qualifyRedundancyCheck(callToCheck, comparedCall)) { if (callToCheck == comparedCall) { bugReporter_.reportRedundantCall(callToCheck.callExpr(), comparedCall.callExpr()); callToCheck.isMarked_ = true; callToCheck.isMarked_ = true; } } } return; }