aboutsummaryrefslogtreecommitdiff
path: root/clang-tidy/readability
diff options
context:
space:
mode:
authorFangrui Song <maskray@google.com>2018-02-15 17:56:43 +0000
committerFangrui Song <maskray@google.com>2018-02-15 17:56:43 +0000
commit95c2e1826097c5f3a41243d92d6286885d9acb6d (patch)
tree59720fddf5d2bdeed28b07ccfc550c12c43021b4 /clang-tidy/readability
parent71fa6dfba5c2a003cb3ddcf8475cb8666bf5a671 (diff)
[clang-tidy] Add `readability-simd-intrinsics` check.
Summary: Many architectures provide SIMD operations (e.g. x86 SSE/AVX, Power AltiVec/VSX, ARM NEON). It is common that SIMD code implementing the same algorithm, is written in multiple target-dispatching pieces to optimize for different architectures or micro-architectures. The C++ standard proposal P0214 and its extensions cover many common SIMD operations. By migrating from target-dependent intrinsics to P0214 operations, the SIMD code can be simplified and pieces for different targets can be unified. Refer to http://wg21.link/p0214 for introduction and motivation for the data-parallel standard library. Subscribers: klimek, aemerson, mgorny, xazax.hun, kristof.beyls, hintonda, cfe-commits Differential Revision: https://reviews.llvm.org/D42983 git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@325272 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'clang-tidy/readability')
-rw-r--r--clang-tidy/readability/CMakeLists.txt1
-rw-r--r--clang-tidy/readability/ReadabilityTidyModule.cpp3
-rw-r--r--clang-tidy/readability/SIMDIntrinsicsCheck.cpp152
-rw-r--r--clang-tidy/readability/SIMDIntrinsicsCheck.h40
4 files changed, 196 insertions, 0 deletions
diff --git a/clang-tidy/readability/CMakeLists.txt b/clang-tidy/readability/CMakeLists.txt
index 95769ee9..d750626f 100644
--- a/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tidy/readability/CMakeLists.txt
@@ -24,6 +24,7 @@ add_clang_library(clangTidyReadabilityModule
RedundantStringCStrCheck.cpp
RedundantSmartptrGetCheck.cpp
RedundantStringInitCheck.cpp
+ SIMDIntrinsicsCheck.cpp
SimplifyBooleanExprCheck.cpp
StaticAccessedThroughInstanceCheck.cpp
StaticDefinitionInAnonymousNamespaceCheck.cpp
diff --git a/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tidy/readability/ReadabilityTidyModule.cpp
index f39e4a1e..619a4482 100644
--- a/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -31,6 +31,7 @@
#include "RedundantSmartptrGetCheck.h"
#include "RedundantStringCStrCheck.h"
#include "RedundantStringInitCheck.h"
+#include "SIMDIntrinsicsCheck.h"
#include "SimplifyBooleanExprCheck.h"
#include "StaticAccessedThroughInstanceCheck.h"
#include "StaticDefinitionInAnonymousNamespaceCheck.h"
@@ -92,6 +93,8 @@ public:
"readability-redundant-string-cstr");
CheckFactories.registerCheck<RedundantStringInitCheck>(
"readability-redundant-string-init");
+ CheckFactories.registerCheck<SIMDIntrinsicsCheck>(
+ "readability-simd-intrinsics");
CheckFactories.registerCheck<SimplifyBooleanExprCheck>(
"readability-simplify-boolean-expr");
CheckFactories.registerCheck<UniqueptrDeleteReleaseCheck>(
diff --git a/clang-tidy/readability/SIMDIntrinsicsCheck.cpp b/clang-tidy/readability/SIMDIntrinsicsCheck.cpp
new file mode 100644
index 00000000..123e76d7
--- /dev/null
+++ b/clang-tidy/readability/SIMDIntrinsicsCheck.cpp
@@ -0,0 +1,152 @@
+//===--- SIMDIntrinsicsCheck.cpp - clang-tidy------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SIMDIntrinsicsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Regex.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+namespace {
+
+// If the callee has parameter of VectorType or pointer to VectorType,
+// or the return type is VectorType, we consider it a vector function
+// and a candidate for checking.
+AST_MATCHER(FunctionDecl, isVectorFunction) {
+ bool IsVector = Node.getReturnType()->isVectorType();
+ for (const ParmVarDecl *Parm : Node.parameters()) {
+ QualType Type = Parm->getType();
+ if (Type->isPointerType())
+ Type = Type->getPointeeType();
+ if (Type->isVectorType())
+ IsVector = true;
+ }
+ return IsVector;
+}
+
+} // namespace
+
+static StringRef TrySuggestPPC(StringRef Name) {
+ if (!Name.consume_front("vec_"))
+ return {};
+
+ static const llvm::StringMap<StringRef> Mapping{
+ // [simd.alg]
+ {"max", "$std::max"},
+ {"min", "$std::min"},
+
+ // [simd.binary]
+ {"add", "operator+ on $simd objects"},
+ {"sub", "operator- on $simd objects"},
+ {"mul", "operator* on $simd objects"},
+ };
+
+ auto It = Mapping.find(Name);
+ if (It != Mapping.end())
+ return It->second;
+ return {};
+}
+
+static StringRef TrySuggestX86(StringRef Name) {
+ if (!(Name.consume_front("_mm_") || Name.consume_front("_mm256_") ||
+ Name.consume_front("_mm512_")))
+ return {};
+
+ // [simd.alg]
+ if (Name.startswith("max_"))
+ return "$simd::max";
+ if (Name.startswith("min_"))
+ return "$simd::min";
+
+ // [simd.binary]
+ if (Name.startswith("add_"))
+ return "operator+ on $simd objects";
+ if (Name.startswith("sub_"))
+ return "operator- on $simd objects";
+ if (Name.startswith("mul_"))
+ return "operator* on $simd objects";
+
+ return {};
+}
+
+SIMDIntrinsicsCheck::SIMDIntrinsicsCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context), Suggest(Options.get("Suggest", 0) != 0) {}
+
+void SIMDIntrinsicsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "Suggest", 0);
+}
+
+void SIMDIntrinsicsCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+ // libcxx implementation backports it to C++11 std::experimental::simd.
+ Std = getLangOpts().CPlusPlus2a ? "std" : "std::experimental";
+
+ Finder->addMatcher(callExpr(callee(functionDecl(allOf(
+ matchesName("^::(_mm_|_mm256_|_mm512_|vec_)"),
+ isVectorFunction()))),
+ unless(isExpansionInSystemHeader()))
+ .bind("call"),
+ this);
+}
+
+void SIMDIntrinsicsCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+ assert(Call != nullptr);
+ const FunctionDecl *Callee = Call->getDirectCallee();
+ if (!Callee)
+ return;
+
+ StringRef Old = Callee->getName();
+ StringRef New;
+ llvm::Triple::ArchType Arch =
+ Result.Context->getTargetInfo().getTriple().getArch();
+
+ switch (Arch) {
+ default:
+ break;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ New = TrySuggestPPC(Old);
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ New = TrySuggestX86(Old);
+ break;
+ }
+
+ if (!New.empty()) {
+ std::string Message;
+ // If Suggest is true, give a P0214 alternative, otherwise point it out it
+ // is non-portable.
+ if (Suggest) {
+ Message = (Twine("'") + Old + "' can be replaced by " + New).str();
+ Message = llvm::Regex("\\$std").sub(Std, Message);
+ Message = llvm::Regex("\\$simd").sub(Std.str() + "::simd", Message);
+ } else {
+ Message = (Twine("'") + Old + "' is a non-portable " +
+ llvm::Triple::getArchTypeName(Arch) + " intrinsic function")
+ .str();
+ }
+ diag(Call->getExprLoc(), Message);
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tidy/readability/SIMDIntrinsicsCheck.h b/clang-tidy/readability/SIMDIntrinsicsCheck.h
new file mode 100644
index 00000000..8c36cd7d
--- /dev/null
+++ b/clang-tidy/readability/SIMDIntrinsicsCheck.h
@@ -0,0 +1,40 @@
+//===--- SIMDIntrinsicsCheck.h - clang-tidy----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SIMD_INTRINSICS_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SIMD_INTRINSICS_CHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Find SIMD intrinsics calls and suggest std::experimental::simd alternatives.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-simd-intrinsics.html
+class SIMDIntrinsicsCheck : public ClangTidyCheck {
+public:
+ SIMDIntrinsicsCheck(StringRef Name, ClangTidyContext *Context);
+
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+ private:
+ const bool Suggest;
+ StringRef Std;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SIMD_INTRINSICS_CHECK_H