Skip to content

Wrote some basic tests for kokkos-implicit-this-capture #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 10 additions & 14 deletions clang-tools-extra/clang-tidy/kokkos/ImplicitThisCaptureCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,37 +39,34 @@ llvm::Optional<SourceLocation> capturesThis(CXXRecordDecl const *CRD) {

} // namespace

ImplicitThisCaptureCheck::ImplicitThisCaptureCheck(
StringRef Name, ClangTidyContext *Context)
ImplicitThisCaptureCheck::ImplicitThisCaptureCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {
CheckIfExplicitHost = std::stoi(Options.get("CheckIfExplicitHost", "0"));
HostTypeDefRegex =
Options.get("HostTypeDefRegex", "Kokkos::DefaultHostExecutionSpace");
}

void ImplicitThisCaptureCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
void ImplicitThisCaptureCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "CheckIfExplicitHost",
std::to_string(CheckIfExplicitHost));
Options.store(Opts, "HostTypeDefRegex", HostTypeDefRegex);
}

void ImplicitThisCaptureCheck::registerMatchers(MatchFinder *Finder) {
auto isAllowedPolicy = expr(hasType(
cxxRecordDecl(matchesName("::Impl::ThreadVectorRangeBoundariesStruct.*|::"
"Impl::TeamThreadRangeBoundariesStruct.*"))));
cxxRecordDecl(matchesName("::Impl::ThreadVectorRangeBoundariesStruct.*|"
"::Impl::TeamThreadRangeBoundariesStruct.*"))));

auto Lambda = expr(hasType(cxxRecordDecl(isLambda()).bind("Lambda")));

Finder->addMatcher(
callExpr(isKokkosParallelCall(),
hasAnyArgument(Lambda), unless(hasAnyArgument(isAllowedPolicy)))
.bind("x"),
this);
Finder->addMatcher(callExpr(isKokkosParallelCall(), hasAnyArgument(Lambda),
unless(hasAnyArgument(isAllowedPolicy)))
.bind("x"),
this);
}

void ImplicitThisCaptureCheck::check(
const MatchFinder::MatchResult &Result) {
void ImplicitThisCaptureCheck::check(const MatchFinder::MatchResult &Result) {
auto const *CE = Result.Nodes.getNodeAs<CallExpr>("x");

if (CheckIfExplicitHost) {
Expand All @@ -85,7 +82,6 @@ void ImplicitThisCaptureCheck::check(
<< CE->getDirectCallee()->getName();
diag(CaptureLocation.getValue(), "the captured variable is used here.",
DiagnosticIDs::Note);
diag(CE->getBeginLoc(), "Kokkos call here.", DiagnosticIDs::Note);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that the only real change here, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was formatting, and also I changed the string for the regex for isAllowedPolicy slightly.

}
}

Expand Down
4 changes: 2 additions & 2 deletions clang-tools-extra/clang-tidy/kokkos/KokkosMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ AST_MATCHER(CallExpr, isKokkosParallelCall) {
if (auto const *FD = Node.getDirectCallee()) {
std::string Name = FD->getQualifiedNameAsString();
StringRef SR(Name);
if (SR.startswith("::Kokkos::parallel_")) {
if (SR.startswith("::Kokkos::parallel_") ||
SR.startswith("Kokkos::parallel_")) {
return true;
}
}
Expand All @@ -44,7 +45,6 @@ AST_MATCHER(CallExpr, isKokkosParallelCall) {
bool explicitlyUsingHostExecutionSpace(CallExpr const *CE,
std::string const &RegexString);


} // namespace kokkos
} // namespace tidy
} // namespace clang
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#pragma once

//
// Standard library stuff that shows up in Kokkos
//
namespace std {
struct string {
string(const char *);
~string();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to bother with the destructor?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copy pasted this from a different check, we can remove it. The mocking is specifically not finalized, I am just trying to get it working and will expand it as needed.

};
} // namespace std

//
// Global things that show up in Kokkos
//
using size_t = decltype(sizeof(int));
int printf(const char *format, ...);

//
// Kokkos macros
//
#define KOKKOS_LAMBDA [=]
#define KOKKOS_FUNCTION __attribute__((annotate("KOKKOS_FUNCTION")))
#define KOKKOS_INLINE_FUNCTION __attribute__((annotate("KOKKOS_INLINE_FUNCTION")))
#define KOKKOS_FORCEINLINE_FUNCTION __attribute__((annotate("KOKKOS_FORCEINLINE_FUNCTION")))

//
// Kokkos public and semi-public API
//
namespace Kokkos {
namespace Impl {
template <typename IndexType, typename MemberType>
struct TeamThreadRangeBoundariesStruct {
KOKKOS_INLINE_FUNCTION
TeamThreadRangeBoundariesStruct(MemberType const &m,
IndexType const &arg_end) {}
};

template <typename IndexType, typename MemberType>
struct ThreadVectorRangeBoundariesStruct {
KOKKOS_INLINE_FUNCTION
ThreadVectorRangeBoundariesStruct(MemberType const &m,
IndexType const &arg_end) {}
};
} // namespace Impl

template <class FunctorType>
inline void parallel_for(const size_t work_count,
const FunctorType &functor,
const std::string &str = "") {}

template <class ExecPolicy, class FunctorType>
inline void parallel_for(const std::string &str,
const ExecPolicy &policy,
const FunctorType &functor) {}

template <class ExecPolicy, class FunctorType>
inline void parallel_for(const ExecPolicy &policy,
const FunctorType &functor,
std::string const &str = "") {}

template <class... Properties>
class TeamPolicy {
public:
using member_type = int;
};

template <typename iType>
KOKKOS_INLINE_FUNCTION
Impl::TeamThreadRangeBoundariesStruct<iType, TeamPolicy<>::member_type>
TeamThreadRange(const TeamPolicy<>::member_type &thread, iType count) {
return Impl::TeamThreadRangeBoundariesStruct<iType,
TeamPolicy<>::member_type>(thread, count);
}

template <typename iType>
KOKKOS_INLINE_FUNCTION
Impl::ThreadVectorRangeBoundariesStruct<iType, TeamPolicy<>::member_type>
ThreadVectorRange(const TeamPolicy<>::member_type &thread, iType count) {
return Impl::ThreadVectorRangeBoundariesStruct<iType,
TeamPolicy<>::member_type>(thread, count);
}

namespace Impl {
struct SomeHostExecutionSpace {};

template <typename... Properties>
struct PolicyTraits{};
} // namespace Impl

using DefaultExecutionSpace = Impl::SomeHostExecutionSpace;
using DefaultHostExecutionSpace = Impl::SomeHostExecutionSpace;

template <class... Properties>
class RangePolicy : public Impl::PolicyTraits<Properties...>{
public:
RangePolicy(int, int) {}
};

} // namespace Kokkos
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// RUN: %check_clang_tidy %s kokkos-implicit-this-capture %t -- -config="{CheckOptions: [{key: kokkos-implicit-this-capture.CheckIfExplicitHost, value: 1}]}" -header-filter=.* -system-headers -- -isystem %S/Inputs/kokkos/

#include "Kokkos_Core_mock.h"

KOKKOS_FUNCTION void do_something(int x) { printf("Got int %d\n", x); }

class BadClass {
int MyInt = 0;

public:
void capturesThis() {
Kokkos::parallel_for(
Kokkos::RangePolicy<Kokkos::DefaultExecutionSpace>(0,10),
[=](int) { do_something(MyInt); });
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Lambda passed to parallel_for implicitly captures this. [kokkos-implicit-this-capture]
}
};

class GoodClass {
int MyInt = 0;

public:
void capturesThis() {
Kokkos::parallel_for(
Kokkos::RangePolicy<Kokkos::DefaultHostExecutionSpace>(0,10),
KOKKOS_LAMBDA(int) { do_something(MyInt); });
}
};
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
// RUN: %check_clang_tidy %s kokkos-implicit-this-capture %t
// RUN: %check_clang_tidy %s kokkos-implicit-this-capture %t -- -header-filter=.* -system-headers -- -isystem %S/Inputs/kokkos/

// TODO Need to mock Kokkos
// FIXME: Add something that triggers the check here.
// void f();
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [kokkos-implicit-this-capture]
#include "Kokkos_Core_mock.h"

// FIXME: Verify the applied fix.
// * Make the CHECK patterns specific enough and try to make verified lines
// unique to avoid incorrect matches.
// * Use {{}} for regular expressions.
// CHECK-FIXES: {{^}}void awesome_f();{{$}}
KOKKOS_FUNCTION void do_something(int x) { printf("Got int %d\n", x); }
using TeamMember = Kokkos::TeamPolicy<>::member_type;
class BadClass {
int my_int;

// FIXME: Add something that doesn't trigger the check here.
// void awesome_f2();
public:
void capturesThis() {
Kokkos::parallel_for(
10, KOKKOS_LAMBDA(int x) { my_int = x; });
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: Lambda passed to parallel_for implicitly captures this. [kokkos-implicit-this-capture]
}
};

// Should not warn
struct GoodClass {
int foo;
TeamMember member;

KOKKOS_INLINE_FUNCTION void method() {
auto TTR = Kokkos::TeamThreadRange(member, 15);
Kokkos::parallel_for(TTR, [&](int i) {
auto TVR = Kokkos::ThreadVectorRange(member, 3);
auto func = [&](int j) {
do_something(foo);
do_something(i + j);
};
Kokkos::parallel_for(TVR, func);
});
}
};