diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt --- a/clang/include/clang/Basic/CMakeLists.txt +++ b/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) diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def --- a/clang/include/clang/Basic/TokenKinds.def +++ b/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) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -212,6 +212,7 @@ std::unique_ptr AttributePragmaHandler; std::unique_ptr MaxTokensHerePragmaHandler; std::unique_ptr MaxTokensTotalPragmaHandler; + std::unique_ptr RISCVPragmaHandler; std::unique_ptr CommentSemaHandler; diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/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 Toks) { for (auto &T : Toks) T.setFlag(clang::Token::IsReinjected); @@ -495,6 +501,11 @@ MaxTokensTotalPragmaHandler = std::make_unique(); PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get()); + + if (getTargetInfo().getTriple().isRISCV()) { + RISCVPragmaHandler = std::make_unique(); + 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"); +} diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp --- a/clang/lib/Sema/SemaLookup.cpp +++ b/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 #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 diff --git a/clang/utils/TableGen/RISCVVEmitter.cpp b/clang/utils/TableGen/RISCVVEmitter.cpp --- a/clang/utils/TableGen/RISCVVEmitter.cpp +++ b/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 PrototypeSeq); Optional 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> &Defs, raw_ostream &o, - std::function); - - // 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> &Defs, raw_ostream &OS, - std::function 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> 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 diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp --- a/clang/utils/TableGen/TableGen.cpp +++ b/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; diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h --- a/clang/utils/TableGen/TableGenBackends.h +++ b/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); diff --git a/llvm/docs/CommandGuide/tblgen.rst b/llvm/docs/CommandGuide/tblgen.rst --- a/llvm/docs/CommandGuide/tblgen.rst +++ b/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.