brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.5 KiB · fb4b22c Raw
146 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "SIMDIntrinsicsCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12#include "clang/Basic/TargetInfo.h"13#include "llvm/Support/Regex.h"14#include "llvm/TargetParser/Triple.h"15 16using namespace clang::ast_matchers;17 18namespace clang::tidy::portability {19 20namespace {21 22// If the callee has parameter of VectorType or pointer to VectorType,23// or the return type is VectorType, we consider it a vector function24// and a candidate for checking.25AST_MATCHER(FunctionDecl, isVectorFunction) {26  bool IsVector = Node.getReturnType()->isVectorType();27  for (const ParmVarDecl *Parm : Node.parameters()) {28    QualType Type = Parm->getType();29    if (Type->isPointerType())30      Type = Type->getPointeeType();31    if (Type->isVectorType())32      IsVector = true;33  }34  return IsVector;35}36 37} // namespace38 39static StringRef trySuggestPpc(StringRef Name) {40  if (!Name.consume_front("vec_"))41    return {};42 43  return llvm::StringSwitch<StringRef>(Name)44      // [simd.alg]45      .Case("max", "$std::max")46      .Case("min", "$std::min")47      // [simd.binary]48      .Case("add", "operator+ on $simd objects")49      .Case("sub", "operator- on $simd objects")50      .Case("mul", "operator* on $simd objects")51      .Default({});52}53 54static StringRef trySuggestX86(StringRef Name) {55  if (!(Name.consume_front("_mm_") || Name.consume_front("_mm256_") ||56        Name.consume_front("_mm512_")))57    return {};58 59  // [simd.alg]60  if (Name.starts_with("max_"))61    return "$simd::max";62  if (Name.starts_with("min_"))63    return "$simd::min";64 65  // [simd.binary]66  if (Name.starts_with("add_"))67    return "operator+ on $simd objects";68  if (Name.starts_with("sub_"))69    return "operator- on $simd objects";70  if (Name.starts_with("mul_"))71    return "operator* on $simd objects";72 73  return {};74}75 76SIMDIntrinsicsCheck::SIMDIntrinsicsCheck(StringRef Name,77                                         ClangTidyContext *Context)78    : ClangTidyCheck(Name, Context), Std(Options.get("Std", "")),79      Suggest(Options.get("Suggest", false)) {}80 81void SIMDIntrinsicsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {82  Options.store(Opts, "Std", Std);83  Options.store(Opts, "Suggest", Suggest);84}85 86void SIMDIntrinsicsCheck::registerMatchers(MatchFinder *Finder) {87  // If Std is not specified, infer it from the language options.88  // libcxx implementation backports it to C++11 std::experimental::simd.89  if (Std.empty())90    Std = getLangOpts().CPlusPlus20 ? "std" : "std::experimental";91 92  Finder->addMatcher(callExpr(callee(functionDecl(93                                  matchesName("^::(_mm_|_mm256_|_mm512_|vec_)"),94                                  isVectorFunction())),95                              unless(isExpansionInSystemHeader()))96                         .bind("call"),97                     this);98}99 100void SIMDIntrinsicsCheck::check(const MatchFinder::MatchResult &Result) {101  const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");102  assert(Call != nullptr);103  const FunctionDecl *Callee = Call->getDirectCallee();104  if (!Callee)105    return;106 107  const StringRef Old = Callee->getName();108  StringRef New;109  const llvm::Triple::ArchType Arch =110      Result.Context->getTargetInfo().getTriple().getArch();111 112  // We warn or suggest if this SIMD intrinsic function has a std::simd113  // replacement.114  switch (Arch) {115  default:116    break;117  case llvm::Triple::ppc:118  case llvm::Triple::ppc64:119  case llvm::Triple::ppc64le:120    New = trySuggestPpc(Old);121    break;122  case llvm::Triple::x86:123  case llvm::Triple::x86_64:124    New = trySuggestX86(Old);125    break;126  }127 128  // We have found a std::simd replacement.129  if (!New.empty()) {130    // If Suggest is true, give a P0214 alternative, otherwise point it out it131    // is non-portable.132    if (Suggest) {133      static const llvm::Regex StdRegex("\\$std"), SimdRegex("\\$simd");134      diag(Call->getExprLoc(), "'%0' can be replaced by %1")135          << Old136          << SimdRegex.sub(SmallString<32>({Std, "::simd"}),137                           StdRegex.sub(Std, New));138    } else {139      diag(Call->getExprLoc(), "'%0' is a non-portable %1 intrinsic function")140          << Old << llvm::Triple::getArchTypeName(Arch);141    }142  }143}144 145} // namespace clang::tidy::portability146