HsiangKai created this revision.
HsiangKai added reviewers: khchen, craig.topper, rogfer01, kito-cheng.
Herald added subscribers: achieveartificialintelligence, StephenFan, vkmr, 
frasercrmck, dexonsmith, evandro, luismarques, apazos, sameer.abuasal, 
s.egerton, Jim, benna, psnobl, jocewei, PkmX, the_o, brucehoult, MartinMosbeck, 
edward-jones, zzheng, jrtc27, shiva0217, niosHD, sabuasal, simoncook, 
johnrusso, rbar, asb, Anastasia, mgorny.
HsiangKai requested review of this revision.
Herald added subscribers: llvm-commits, cfe-commits, MaskRay.
Herald added projects: clang, LLVM.

Leverage the method OpenCL uses that adds C intrinsics when the lookup
failed. There is no need to define C intrinsics in the header file any
more. It could help to avoid the large header file to speed up the
compilation of RVV source code. Besides that, only the C intrinsics used
by the users will be added into the declaration table.

This patch is based on https://reviews.llvm.org/D103228 and inspired by
OpenCL implementation.

Authored-by: Kito Cheng <kito.ch...@sifive.com>
Co-Authored-by: Hsiangkai Wang <kai.w...@sifive.com>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D111617

Files:
  clang/include/clang/Basic/CMakeLists.txt
  clang/include/clang/Basic/TokenKinds.def
  clang/include/clang/Parse/Parser.h
  clang/lib/Parse/ParsePragma.cpp
  clang/lib/Sema/SemaLookup.cpp
  clang/utils/TableGen/RISCVVEmitter.cpp
  clang/utils/TableGen/TableGen.cpp
  clang/utils/TableGen/TableGenBackends.h
  llvm/docs/CommandGuide/tblgen.rst

Index: llvm/docs/CommandGuide/tblgen.rst
===================================================================
--- llvm/docs/CommandGuide/tblgen.rst
+++ llvm/docs/CommandGuide/tblgen.rst
@@ -348,6 +348,10 @@
 
   Generate ``riscv_vector_builtin_cg.inc`` for Clang.
 
+.. option:: -gen-riscv-vector-builtin-sema
+
+  Generate ``riscv_vector_builtin_sema.inc`` for Clang.
+
 .. option:: -gen-attr-docs
 
   Generate attribute documentation.
Index: clang/utils/TableGen/TableGenBackends.h
===================================================================
--- clang/utils/TableGen/TableGenBackends.h
+++ clang/utils/TableGen/TableGenBackends.h
@@ -110,6 +110,7 @@
 void EmitRVVHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
 void EmitRVVBuiltins(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
 void EmitRVVBuiltinCG(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
+void EmitRVVBuiltinSema(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
 
 void EmitCdeHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
 void EmitCdeBuiltinDef(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
Index: clang/utils/TableGen/TableGen.cpp
===================================================================
--- clang/utils/TableGen/TableGen.cpp
+++ clang/utils/TableGen/TableGen.cpp
@@ -88,6 +88,7 @@
   GenRISCVVectorHeader,
   GenRISCVVectorBuiltins,
   GenRISCVVectorBuiltinCG,
+  GenRISCVVectorBuiltinSema,
   GenAttrDocs,
   GenDiagDocs,
   GenOptDocs,
@@ -243,6 +244,8 @@
                    "Generate riscv_vector_builtins.inc for clang"),
         clEnumValN(GenRISCVVectorBuiltinCG, "gen-riscv-vector-builtin-codegen",
                    "Generate riscv_vector_builtin_cg.inc for clang"),
+        clEnumValN(GenRISCVVectorBuiltinSema, "gen-riscv-vector-builtin-sema",
+                   "Generate riscv_vector_builtin_sema.inc for clang"),
         clEnumValN(GenAttrDocs, "gen-attr-docs",
                    "Generate attribute documentation"),
         clEnumValN(GenDiagDocs, "gen-diag-docs",
@@ -458,6 +461,9 @@
   case GenRISCVVectorBuiltinCG:
     EmitRVVBuiltinCG(Records, OS);
     break;
+  case GenRISCVVectorBuiltinSema:
+    EmitRVVBuiltinSema(Records, OS);
+    break;
   case GenAttrDocs:
     EmitClangAttrDocs(Records, OS);
     break;
Index: clang/utils/TableGen/RISCVVEmitter.cpp
===================================================================
--- clang/utils/TableGen/RISCVVEmitter.cpp
+++ clang/utils/TableGen/RISCVVEmitter.cpp
@@ -203,12 +203,6 @@
   // Emit the code block for switch body in EmitRISCVBuiltinExpr, it should
   // init the RVVIntrinsic ID and IntrinsicTypes.
   void emitCodeGenSwitchBody(raw_ostream &o) const;
-
-  // Emit the macros for mapping C/C++ intrinsic function to builtin functions.
-  void emitIntrinsicMacro(raw_ostream &o) const;
-
-  // Emit the mangled function definition.
-  void emitMangledFuncDef(raw_ostream &o) const;
 };
 
 class RVVEmitter {
@@ -231,6 +225,9 @@
   /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
   void createCodeGen(raw_ostream &o);
 
+  /// Emit all the information needed by SemaLookup.cpp.
+  void createSema(raw_ostream &o);
+
   std::string getSuffixStr(char Type, int Log2LMUL, StringRef Prototypes);
 
 private:
@@ -246,15 +243,6 @@
                                   ArrayRef<std::string> PrototypeSeq);
   Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, StringRef Proto);
 
-  /// Emit Acrh predecessor definitions and body, assume the element of Defs are
-  /// sorted by extension.
-  void emitArchMacroAndBody(
-      std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o,
-      std::function<void(raw_ostream &, const RVVIntrinsic &)>);
-
-  // Emit the architecture preprocessor definitions. Return true when emits
-  // non-empty string.
-  bool emitExtDefStr(uint8_t Extensions, raw_ostream &o);
   // Slice Prototypes string into sub prototype string and process each sub
   // prototype string individually in the Handler.
   void parsePrototypes(StringRef Prototypes,
@@ -873,36 +861,6 @@
   OS << "  break;\n";
 }
 
-void RVVIntrinsic::emitIntrinsicMacro(raw_ostream &OS) const {
-  OS << "#define " << getName() << "(";
-  if (!InputTypes.empty()) {
-    ListSeparator LS;
-    for (unsigned i = 0, e = InputTypes.size(); i != e; ++i)
-      OS << LS << "op" << i;
-  }
-  OS << ") \\\n";
-  OS << "__builtin_rvv_" << getName() << "(";
-  if (!InputTypes.empty()) {
-    ListSeparator LS;
-    for (unsigned i = 0, e = InputTypes.size(); i != e; ++i)
-      OS << LS << "(" << InputTypes[i]->getTypeStr() << ")(op" << i << ")";
-  }
-  OS << ")\n";
-}
-
-void RVVIntrinsic::emitMangledFuncDef(raw_ostream &OS) const {
-  OS << "__attribute__((clang_builtin_alias(";
-  OS << "__builtin_rvv_" << getName() << ")))\n";
-  OS << OutputType->getTypeStr() << " " << getMangledName() << "(";
-  // Emit function arguments
-  if (!InputTypes.empty()) {
-    ListSeparator LS;
-    for (unsigned i = 0; i < InputTypes.size(); ++i)
-      OS << LS << InputTypes[i]->getTypeStr() << " op" << i;
-  }
-  OS << ");\n\n";
-}
-
 //===----------------------------------------------------------------------===//
 // RVVEmitter implementation
 //===----------------------------------------------------------------------===//
@@ -934,6 +892,7 @@
   OS << "#ifdef __cplusplus\n";
   OS << "extern \"C\" {\n";
   OS << "#endif\n\n";
+  OS << "#pragma riscv intrinsic vector\n\n";
 
   createRVVHeaders(OS);
 
@@ -999,24 +958,8 @@
                      return A->getRISCVExtensions() < B->getRISCVExtensions();
                    });
 
-  // Print intrinsic functions with macro
-  emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
-    Inst.emitIntrinsicMacro(OS);
-  });
-
   OS << "#define __riscv_v_intrinsic_overloading 1\n";
 
-  // Print Overloaded APIs
-  OS << "#define __rvv_overloaded static inline "
-        "__attribute__((__always_inline__, __nodebug__, __overloadable__))\n";
-
-  emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
-    if (!Inst.isMask() && !Inst.hasNoMaskedOverloaded())
-      return;
-    OS << "__rvv_overloaded ";
-    Inst.emitMangledFuncDef(OS);
-  });
-
   OS << "\n#ifdef __cplusplus\n";
   OS << "}\n";
   OS << "#endif // __riscv_vector\n";
@@ -1273,43 +1216,68 @@
   return llvm::None;
 }
 
-void RVVEmitter::emitArchMacroAndBody(
-    std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS,
-    std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) {
-  uint8_t PrevExt = (*Defs.begin())->getRISCVExtensions();
-  bool NeedEndif = emitExtDefStr(PrevExt, OS);
-  for (auto &Def : Defs) {
-    uint8_t CurExt = Def->getRISCVExtensions();
-    if (CurExt != PrevExt) {
-      if (NeedEndif)
-        OS << "#endif\n\n";
-      NeedEndif = emitExtDefStr(CurExt, OS);
-      PrevExt = CurExt;
-    }
-    if (Def->hasAutoDef())
-      PrintBody(OS, *Def);
+static void emitFeatureCheckStr(uint8_t Extents, raw_ostream &OS) {
+  if (Extents == RISCVExtension::Basic) {
+    OS << 0;
+    return;
   }
-  if (NeedEndif)
-    OS << "#endif\n\n";
-}
-
-bool RVVEmitter::emitExtDefStr(uint8_t Extents, raw_ostream &OS) {
-  if (Extents == RISCVExtension::Basic)
-    return false;
-  OS << "#if ";
-  ListSeparator LS(" && ");
+  ListSeparator LS("|");
   if (Extents & RISCVExtension::F)
-    OS << LS << "defined(__riscv_f)";
+    OS << LS << "RISCVFeature_F";
   if (Extents & RISCVExtension::D)
-    OS << LS << "defined(__riscv_d)";
+    OS << LS << "RISCVFeature_D";
   if (Extents & RISCVExtension::Zfh)
-    OS << LS << "defined(__riscv_zfh)";
+    OS << LS << "RISCVFeature_ZFH";
   if (Extents & RISCVExtension::Zvamo)
-    OS << LS << "defined(__riscv_zvamo)";
+    OS << LS << "RISCVFeature_ZVAMO";
   if (Extents & RISCVExtension::Zvlsseg)
-    OS << LS << "defined(__riscv_zvlsseg)";
-  OS << "\n";
-  return true;
+    OS << LS << "RISCVFeature_ZVLSSEG";
+}
+
+void RVVEmitter::createSema(raw_ostream &OS) {
+  OS << "enum RISCVFeatures {\n";
+  OS << "  RISCVFeature_F = 1 << 1,\n";
+  OS << "  RISCVFeature_D = 1 << 2,\n";
+  OS << "  RISCVFeature_ZFH = 1 << 3,\n";
+  OS << "  RISCVFeature_ZVAMO = 1 << 4,\n";
+  OS << "  RISCVFeature_ZVLSSEG = 1 << 5,\n";
+  OS << "};\n\n";
+
+  OS << "struct RVVIntrinsicInfo {\n";
+  OS << "  const char *TargetName;\n";
+  OS << "  unsigned TargetBuiltinID;\n";
+  OS << "  unsigned RequireFeatures;\n";
+  OS << "};\n\n";
+
+  OS << "struct RVVIntrinsicOverloadInfo {\n";
+  OS << "  const char *TargetName;\n";
+  OS << "  const char *OverloadName;\n";
+  OS << "  unsigned TargetBuiltinID;\n";
+  OS << "  unsigned RequireFeatures;\n";
+  OS << "};\n\n";
+
+  std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
+  createRVVIntrinsics(Defs);
+  OS << "static const RVVIntrinsicInfo RVVIntrinsicInfos[] = {\n";
+  for (auto &Def : Defs) {
+    OS << "  {\"" << Def->getName() << "\", ";
+    OS << "RISCV::BI__builtin_rvv_" << Def->getName() << ", ";
+    emitFeatureCheckStr(Def->getRISCVExtensions(), OS);
+    OS << "},\n";
+  }
+  OS << "};\n\n";
+
+  OS << "static const RVVIntrinsicOverloadInfo RVVIntrinsicOverloadInfos[] = {\n";
+  for (auto &Def : Defs) {
+    if (!Def->isMask() && !Def->hasNoMaskedOverloaded())
+      continue;
+    OS << "  {\"__builtin_rvv_" << Def->getName() << "\", ";
+    OS << "\"" << Def->getMangledName() << "\", ";
+    OS << "RISCV::BI__builtin_rvv_" << Def->getName() << ", ";
+    emitFeatureCheckStr(Def->getRISCVExtensions(), OS);
+    OS << "},\n";
+  }
+  OS << "};\n\n";
 }
 
 namespace clang {
@@ -1325,4 +1293,8 @@
   RVVEmitter(Records).createCodeGen(OS);
 }
 
+void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) {
+  RVVEmitter(Records).createSema(OS);
+}
+
 } // End namespace clang
Index: clang/lib/Sema/SemaLookup.cpp
===================================================================
--- clang/lib/Sema/SemaLookup.cpp
+++ clang/lib/Sema/SemaLookup.cpp
@@ -23,6 +23,8 @@
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Basic/TargetInfo.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/ModuleLoader.h"
 #include "clang/Lex/Preprocessor.h"
@@ -48,6 +50,7 @@
 #include <vector>
 
 #include "OpenCLBuiltins.inc"
+#include "clang/Basic/riscv_vector_builtin_sema.inc"
 
 using namespace clang;
 using namespace sema;
@@ -896,6 +899,83 @@
     LR.resolveKind();
 }
 
+static bool InsertRVVBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR,
+                                                  IdentifierInfo *II,
+                                                  const TargetInfo &TI,
+                                                  Preprocessor &PP) {
+  bool HasF = TI.hasFeature("f");
+  bool HasD = TI.hasFeature("d");
+  bool HasZfh = TI.hasFeature("experimental-zfh");
+  bool HasZvamo = TI.hasFeature("experimental-zvamo");
+  bool HasZvlsseg = TI.hasFeature("experimental-zvlsseg");
+  unsigned Features = 0;
+  if (HasF)
+    Features |= RISCVFeature_F;
+  if (HasD)
+    Features |= RISCVFeature_D;
+  if (HasZfh)
+    Features |= RISCVFeature_ZFH;
+  if (HasZvamo)
+    Features |= RISCVFeature_ZVAMO;
+  if (HasZvlsseg)
+    Features |= RISCVFeature_ZVLSSEG;
+
+  const RVVIntrinsicInfo *Intrinsic = std::find_if(
+      std::begin(RVVIntrinsicInfos), std::end(RVVIntrinsicInfos),
+      [II](const RVVIntrinsicInfo &RVVII) {
+        return std::strcmp(RVVII.TargetName, II->getName().data()) == 0;
+      });
+  if (Intrinsic != std::end(RVVIntrinsicInfos)) {
+    if ((Intrinsic->RequireFeatures & Features) != Intrinsic->RequireFeatures)
+      return false;
+    if (NamedDecl *FD =
+            S.LazilyCreateBuiltin(II, Intrinsic->TargetBuiltinID, S.TUScope,
+                                  LR.isForRedeclaration(), LR.getNameLoc())) {
+      LR.addDecl(FD);
+      return true;
+    }
+  }
+
+  // Look for overloaded C intrinsics. If we could find one in the
+  // RVVIntrinsicOverloadInfos, go through the table to add all overloaded
+  // versions.
+  const RVVIntrinsicOverloadInfo *OverloadedII = std::find_if(
+      std::begin(RVVIntrinsicOverloadInfos),
+      std::end(RVVIntrinsicOverloadInfos),
+      [II](const RVVIntrinsicOverloadInfo &RVVII) {
+        return std::strcmp(RVVII.OverloadName, II->getName().data()) == 0;
+      });
+  if (OverloadedII == std::end(RVVIntrinsicOverloadInfos))
+    return false;
+
+  bool Found = false;
+  std::for_each(
+      std::begin(RVVIntrinsicOverloadInfos),
+      std::end(RVVIntrinsicOverloadInfos),
+      [&S, &LR, II, &PP, &Found,
+       Features](const RVVIntrinsicOverloadInfo &RVVII) {
+        if (std::strcmp(RVVII.OverloadName, II->getName().data()) == 0) {
+          if ((RVVII.RequireFeatures & Features) != RVVII.RequireFeatures)
+            return;
+          if (NamedDecl *FD = S.LazilyCreateBuiltin(
+                  II, RVVII.TargetBuiltinID, S.TUScope, LR.isForRedeclaration(),
+                  LR.getNameLoc())) {
+            auto &IntrinsicII = PP.getIdentifierTable().get(RVVII.TargetName);
+            FD->addAttr(OverloadableAttr::CreateImplicit(S.Context));
+            FD->addAttr(
+                BuiltinAliasAttr::CreateImplicit(S.Context, &IntrinsicII));
+            LR.addDecl(FD);
+            Found = true;
+          }
+        }
+      });
+
+  if (Found)
+    LR.resolveKind();
+
+  return Found;
+}
+
 /// Lookup a builtin function, when name lookup would otherwise
 /// fail.
 bool Sema::LookupBuiltin(LookupResult &R) {
@@ -928,6 +1008,12 @@
         }
       }
 
+      if (PP.getPredefines() == "#define __riscv_pragma_vector_intrinsics") {
+        const TargetInfo &TI = Context.getTargetInfo();
+        if (InsertRVVBuiltinDeclarationsFromTable(*this, R, II, TI, PP))
+          return true;
+      }
+
       // If this is a builtin on this (or all) targets, create the decl.
       if (unsigned BuiltinID = II->getBuiltinID()) {
         // In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined
Index: clang/lib/Parse/ParsePragma.cpp
===================================================================
--- clang/lib/Parse/ParsePragma.cpp
+++ clang/lib/Parse/ParsePragma.cpp
@@ -356,6 +356,12 @@
                     Token &FirstToken) override;
 };
 
+struct PragmaRISCVHandler : public PragmaHandler {
+  PragmaRISCVHandler() : PragmaHandler("riscv") {}
+  void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
+                    Token &FirstToken) override;
+};
+
 void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) {
   for (auto &T : Toks)
     T.setFlag(clang::Token::IsReinjected);
@@ -495,6 +501,11 @@
 
   MaxTokensTotalPragmaHandler = std::make_unique<PragmaMaxTokensTotalHandler>();
   PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
+
+  if (getTargetInfo().getTriple().isRISCV()) {
+    RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>();
+    PP.AddPragmaHandler(RISCVPragmaHandler.get());
+  }
 }
 
 void Parser::resetPragmaHandlers() {
@@ -615,6 +626,11 @@
 
   PP.RemovePragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
   MaxTokensTotalPragmaHandler.reset();
+
+  if (getTargetInfo().getTriple().isRISCV()) {
+    PP.RemovePragmaHandler(RISCVPragmaHandler.get());
+    RISCVPragmaHandler.reset();
+  }
 }
 
 /// Handle the annotation token produced for #pragma unused(...)
@@ -3798,3 +3814,27 @@
 
   PP.overrideMaxTokens(MaxTokens, Loc);
 }
+
+// Handle '#pragma riscv intrinsic vector'.
+void PragmaRISCVHandler::HandlePragma(Preprocessor &PP,
+                                      PragmaIntroducer Introducer,
+                                      Token &FirstToken) {
+  Token Tok;
+  PP.Lex(Tok);
+  IdentifierInfo *II = Tok.getIdentifierInfo();
+  if (!II || (!II->isStr("intrinsic"))) {
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
+        << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << "'intrinsic'";
+    return;
+  }
+
+  PP.Lex(Tok);
+  II = Tok.getIdentifierInfo();
+  if (!II || (!II->isStr("vector"))) {
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
+        << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << "'vector'";
+    return;
+  }
+
+  PP.setPredefines("#define __riscv_pragma_vector_intrinsics");
+}
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -212,6 +212,7 @@
   std::unique_ptr<PragmaHandler> AttributePragmaHandler;
   std::unique_ptr<PragmaHandler> MaxTokensHerePragmaHandler;
   std::unique_ptr<PragmaHandler> MaxTokensTotalPragmaHandler;
+  std::unique_ptr<PragmaHandler> RISCVPragmaHandler;
 
   std::unique_ptr<CommentHandler> CommentSemaHandler;
 
Index: clang/include/clang/Basic/TokenKinds.def
===================================================================
--- clang/include/clang/Basic/TokenKinds.def
+++ clang/include/clang/Basic/TokenKinds.def
@@ -887,6 +887,9 @@
 // Annotation for the attribute pragma directives - #pragma clang attribute ...
 PRAGMA_ANNOTATION(pragma_attribute)
 
+// Annotation for the riscv pragma directives - #pragma riscv intrinsic ...
+PRAGMA_ANNOTATION(pragma_riscv)
+
 // Annotations for module import translated from #include etc.
 ANNOTATION(module_include)
 ANNOTATION(module_begin)
Index: clang/include/clang/Basic/CMakeLists.txt
===================================================================
--- clang/include/clang/Basic/CMakeLists.txt
+++ clang/include/clang/Basic/CMakeLists.txt
@@ -90,3 +90,6 @@
 clang_tablegen(riscv_vector_builtin_cg.inc -gen-riscv-vector-builtin-codegen
   SOURCE riscv_vector.td
   TARGET ClangRISCVVectorBuiltinCG)
+clang_tablegen(riscv_vector_builtin_sema.inc -gen-riscv-vector-builtin-sema
+  SOURCE riscv_vector.td
+  TARGET ClangRISCVVectorBuiltinSema)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to