Esempio n. 1
0
/**
 * Check if communication between first, last rank.
 *
 * @return is matching
 */
bool MPICheckerAST::isFirstLastPair(const MPICall &sendCall,
                                    const MPICall &recvCall,
                                    const MPIRankCase &sendCase,
                                    const MPIRankCase &recvCase) const {
    const auto &rankArgSend = sendCall.arg(MPIPointToPoint::kRank);
    const auto &rankArgRecv = recvCall.arg(MPIPointToPoint::kRank);

    llvm::SmallVector<std::string, 1> firstRank{"0"};
    llvm::SmallVector<std::string, 3> lastRank{"-", MPIProcessCount::encoding,
            "1"};

    // first to last match
    if (sendCase.isFirstRank() && rankArgSend.valueSequence() == lastRank &&
            recvCase.isLastRank() && rankArgRecv.valueSequence() == firstRank) {
        return true;
    }
    // last to first match
    else if (sendCase.isLastRank() &&
             rankArgSend.valueSequence() == firstRank &&
             recvCase.isFirstRank() &&
             rankArgRecv.valueSequence() == lastRank) {
        return true;
    } else {
        return false;
    }
}
Esempio n. 2
0
/**
 * 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;
}
Esempio n. 3
0
/**
 * 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;
}
Esempio n. 4
0
/**
 * 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);
}
Esempio n. 5
0
/**
 * 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;
}
Esempio n. 6
0
/**
 * Check if rank arguments of send, recv pair match.
 *
 * @return is matching
 */
bool MPICheckerAST::rankArgsMatch(const MPICall &sendCall,
                                  const MPICall &recvCall,
                                  const MPIRankCase &sendCase,
                                  const MPIRankCase &recvCase) const {
    // match special case
    if (isFirstLastPair(sendCall, recvCall, sendCase, recvCase)) return true;

    // compare ranks
    const auto &rankArgSend = sendCall.arg(MPIPointToPoint::kRank);
    const auto &rankArgRecv = recvCall.arg(MPIPointToPoint::kRank);

    if (rankArgSend.valueSequence().size() !=
            rankArgRecv.valueSequence().size())
        return false;

    // build sequences without last operator(skip first element)
    const llvm::SmallVector<std::string, 4> sendValSeq{
        rankArgSend.valueSequence().begin() + 1,
        rankArgSend.valueSequence().end()},
    recvValSeq{rankArgRecv.valueSequence().begin() + 1,
               rankArgRecv.valueSequence().end()};

    bool containsSubtraction{false};
    for (size_t i = 0; i < sendValSeq.size(); ++i) {
        if (sendValSeq[i] == "-" || recvValSeq[i] == "-") {
            containsSubtraction = true;
            break;
        }
    }

    // check ordered
    if (containsSubtraction && (sendValSeq != recvValSeq)) return false;
    // check permutation
    if (!containsSubtraction &&
            (!cont::isPermutation(sendValSeq, recvValSeq))) {
        return false;
    }
    // last (value|var|function) must be identical
    if (sendValSeq.back() != recvValSeq.back()) return false;
    // last operator must be inverse
    if (!rankArgSend.isLastOperatorInverse(rankArgRecv)) return false;

    return true;
}
Esempio n. 7
0
/**
 * Checks if two (point to point) 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 MPIRankCase &sendCase,
                                   const MPIRankCase &recvCase) 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.arg(idx) != recvCall.arg(idx)) {
            return false;
        }
    }

    return rankArgsMatch(sendCall, recvCall, sendCase, recvCase);
}
Esempio n. 8
0
/**
 * 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);
    }
}
Esempio n. 9
0
/**
 * 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");
            }
        }
    }
}
Esempio n. 10
0
/**
 * 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;
}
Esempio n. 11
0
/**
 * Check if two calls qualify for a redundancy check.
 *
 * @param callToCheck
 * @param comparedCall
 *
 * @return
 */
bool MPICheckerAST::qualifyRedundancyCheck(const MPICall &callToCheck,
                                           const MPICall &comparedCall) const {
    if (comparedCall.isMarked_) return false;  // to omit double matching
    // do not compare with the call itself
    if (callToCheck.id() == comparedCall.id()) return false;
    if (!((funcClassifier_.isPointToPointType(callToCheck) &&
           funcClassifier_.isPointToPointType(comparedCall)) ||
          (funcClassifier_.isCollectiveType(callToCheck) &&
           funcClassifier_.isCollectiveType(comparedCall))))
        return false;

    if (funcClassifier_.isPointToPointType(callToCheck)) {
        // both must be send or recv types
        return (funcClassifier_.isSendType(callToCheck) &&
                funcClassifier_.isSendType(comparedCall)) ||
               (funcClassifier_.isRecvType(callToCheck) &&
                funcClassifier_.isRecvType(comparedCall));

    } else if (funcClassifier_.isCollectiveType(callToCheck)) {
        // calls must be of the same type
        return (funcClassifier_.isScatterType(callToCheck) &&
                funcClassifier_.isScatterType(comparedCall)) ||

               (funcClassifier_.isGatherType(callToCheck) &&
                funcClassifier_.isGatherType(comparedCall)) ||

               (funcClassifier_.isAlltoallType(callToCheck) &&
                funcClassifier_.isAlltoallType(comparedCall)) ||

               (funcClassifier_.isBcastType(callToCheck) &&
                funcClassifier_.isBcastType(comparedCall)) ||

               (funcClassifier_.isReduceType(callToCheck) &&
                funcClassifier_.isReduceType(comparedCall));
    }
    return false;
}