diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h --- a/clang/include/clang/Basic/Builtins.h +++ b/clang/include/clang/Basic/Builtins.h @@ -26,6 +26,7 @@ class TargetInfo; class IdentifierTable; class LangOptions; +class Sema; enum LanguageID { GNU_LANG = 0x1, // builtin requires GNU mode. @@ -51,12 +52,18 @@ FirstTSBuiltin }; +enum BuiltinKind { ALWAYS_KIND, RISCV_VECTOR_KIND }; + struct Info { const char *Name, *Type, *Attributes, *HeaderName; LanguageID Langs; const char *Features; + const char *Overload; + BuiltinKind Kind; }; +typedef void (*RegisterOverloadBuiltinFunc)(Sema &S, const Info &, unsigned ID); + /// Holds information about both target-independent and /// target-specific builtins, allowing easy queries by clients. /// @@ -79,6 +86,13 @@ /// such. void initializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts); + void initializeTargetBuiltins(IdentifierTable &Table, + const LangOptions &LangOpts, BuiltinKind Kind); + void initializeTargetOverloadBuiltins(Sema &S, + RegisterOverloadBuiltinFunc Func, + const LangOptions &LangOpts, + BuiltinKind Kind); + /// Return the identifier name for the specified builtin, /// e.g. "__builtin_abs". const char *getName(unsigned ID) const { @@ -237,7 +251,7 @@ /// Is this builtin supported according to the given language options? bool builtinIsSupported(const Builtin::Info &BuiltinInfo, - const LangOptions &LangOpts); + const LangOptions &LangOpts, BuiltinKind Kind); /// Helper function for isPrintfLike and isScanfLike. bool isLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg, 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 @@ -875,6 +875,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/Basic/riscv_vector.td b/clang/include/clang/Basic/riscv_vector.td --- a/clang/include/clang/Basic/riscv_vector.td +++ b/clang/include/clang/Basic/riscv_vector.td @@ -114,10 +114,10 @@ // The name of the builtin is defined by the Name attribute (which defaults to // the name of the class) appended (separated with an underscore) the Suffix // attribute. For instance with Name="foo", Suffix = "v" and TypeRange = "il", -// the builtin generated will be __builtin_rvv_foo_i32m1 and -// __builtin_rvv_foo_i64m1 (under LMUL=1). If Suffix contains more than one +// the builtin generated will be foo_i32m1 and +// foo_i64m1 (under LMUL=1). If Suffix contains more than one // type transformer (say "vv") each of the types is separated with an -// underscore as in "__builtin_rvv_foo_i32m1_i32m1". +// underscore as in "foo_i32m1_i32m1". // // The C/C++ prototype of the builtin is defined by the Prototype attribute. // Prototype is a non-empty sequence of type transformers, the first of which @@ -984,62 +984,62 @@ // vsetvl is a macro because for it require constant integers in SEW and LMUL. let HeaderCode = [{ -#define vsetvl_e8mf8(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 5) -#define vsetvl_e8mf4(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 6) -#define vsetvl_e8mf2(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 7) -#define vsetvl_e8m1(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 0) -#define vsetvl_e8m2(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 1) -#define vsetvl_e8m4(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 2) -#define vsetvl_e8m8(avl) __builtin_rvv_vsetvli((size_t)(avl), 0, 3) - -#define vsetvl_e16mf4(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 6) -#define vsetvl_e16mf2(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 7) -#define vsetvl_e16m1(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 0) -#define vsetvl_e16m2(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 1) -#define vsetvl_e16m4(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 2) -#define vsetvl_e16m8(avl) __builtin_rvv_vsetvli((size_t)(avl), 1, 3) - -#define vsetvl_e32mf2(avl) __builtin_rvv_vsetvli((size_t)(avl), 2, 7) -#define vsetvl_e32m1(avl) __builtin_rvv_vsetvli((size_t)(avl), 2, 0) -#define vsetvl_e32m2(avl) __builtin_rvv_vsetvli((size_t)(avl), 2, 1) -#define vsetvl_e32m4(avl) __builtin_rvv_vsetvli((size_t)(avl), 2, 2) -#define vsetvl_e32m8(avl) __builtin_rvv_vsetvli((size_t)(avl), 2, 3) - -#define vsetvl_e64m1(avl) __builtin_rvv_vsetvli((size_t)(avl), 3, 0) -#define vsetvl_e64m2(avl) __builtin_rvv_vsetvli((size_t)(avl), 3, 1) -#define vsetvl_e64m4(avl) __builtin_rvv_vsetvli((size_t)(avl), 3, 2) -#define vsetvl_e64m8(avl) __builtin_rvv_vsetvli((size_t)(avl), 3, 3) +#define vsetvl_e8mf8(avl) vsetvli((size_t)(avl), 0, 5) +#define vsetvl_e8mf4(avl) vsetvli((size_t)(avl), 0, 6) +#define vsetvl_e8mf2(avl) vsetvli((size_t)(avl), 0, 7) +#define vsetvl_e8m1(avl) vsetvli((size_t)(avl), 0, 0) +#define vsetvl_e8m2(avl) vsetvli((size_t)(avl), 0, 1) +#define vsetvl_e8m4(avl) vsetvli((size_t)(avl), 0, 2) +#define vsetvl_e8m8(avl) vsetvli((size_t)(avl), 0, 3) + +#define vsetvl_e16mf4(avl) vsetvli((size_t)(avl), 1, 6) +#define vsetvl_e16mf2(avl) vsetvli((size_t)(avl), 1, 7) +#define vsetvl_e16m1(avl) vsetvli((size_t)(avl), 1, 0) +#define vsetvl_e16m2(avl) vsetvli((size_t)(avl), 1, 1) +#define vsetvl_e16m4(avl) vsetvli((size_t)(avl), 1, 2) +#define vsetvl_e16m8(avl) vsetvli((size_t)(avl), 1, 3) + +#define vsetvl_e32mf2(avl) vsetvli((size_t)(avl), 2, 7) +#define vsetvl_e32m1(avl) vsetvli((size_t)(avl), 2, 0) +#define vsetvl_e32m2(avl) vsetvli((size_t)(avl), 2, 1) +#define vsetvl_e32m4(avl) vsetvli((size_t)(avl), 2, 2) +#define vsetvl_e32m8(avl) vsetvli((size_t)(avl), 2, 3) + +#define vsetvl_e64m1(avl) vsetvli((size_t)(avl), 3, 0) +#define vsetvl_e64m2(avl) vsetvli((size_t)(avl), 3, 1) +#define vsetvl_e64m4(avl) vsetvli((size_t)(avl), 3, 2) +#define vsetvl_e64m8(avl) vsetvli((size_t)(avl), 3, 3) }] in def vsetvli : RVVBuiltin<"", "zzKzKz", "i">; let HeaderCode = [{ -#define vsetvlmax_e8mf8() __builtin_rvv_vsetvlimax(0, 5) -#define vsetvlmax_e8mf4() __builtin_rvv_vsetvlimax(0, 6) -#define vsetvlmax_e8mf2() __builtin_rvv_vsetvlimax(0, 7) -#define vsetvlmax_e8m1() __builtin_rvv_vsetvlimax(0, 0) -#define vsetvlmax_e8m2() __builtin_rvv_vsetvlimax(0, 1) -#define vsetvlmax_e8m4() __builtin_rvv_vsetvlimax(0, 2) -#define vsetvlmax_e8m8() __builtin_rvv_vsetvlimax(0, 3) - -#define vsetvlmax_e16mf4() __builtin_rvv_vsetvlimax(1, 6) -#define vsetvlmax_e16mf2() __builtin_rvv_vsetvlimax(1, 7) -#define vsetvlmax_e16m1() __builtin_rvv_vsetvlimax(1, 0) -#define vsetvlmax_e16m2() __builtin_rvv_vsetvlimax(1, 1) -#define vsetvlmax_e16m4() __builtin_rvv_vsetvlimax(1, 2) -#define vsetvlmax_e16m8() __builtin_rvv_vsetvlimax(1, 3) - -#define vsetvlmax_e32mf2() __builtin_rvv_vsetvlimax(2, 7) -#define vsetvlmax_e32m1() __builtin_rvv_vsetvlimax(2, 0) -#define vsetvlmax_e32m2() __builtin_rvv_vsetvlimax(2, 1) -#define vsetvlmax_e32m4() __builtin_rvv_vsetvlimax(2, 2) -#define vsetvlmax_e32m8() __builtin_rvv_vsetvlimax(2, 3) - -#define vsetvlmax_e64m1() __builtin_rvv_vsetvlimax(3, 0) -#define vsetvlmax_e64m2() __builtin_rvv_vsetvlimax(3, 1) -#define vsetvlmax_e64m4() __builtin_rvv_vsetvlimax(3, 2) -#define vsetvlmax_e64m8() __builtin_rvv_vsetvlimax(3, 3) +#define vsetvlmax_e8mf8() vsetvlimax(0, 5) +#define vsetvlmax_e8mf4() vsetvlimax(0, 6) +#define vsetvlmax_e8mf2() vsetvlimax(0, 7) +#define vsetvlmax_e8m1() vsetvlimax(0, 0) +#define vsetvlmax_e8m2() vsetvlimax(0, 1) +#define vsetvlmax_e8m4() vsetvlimax(0, 2) +#define vsetvlmax_e8m8() vsetvlimax(0, 3) + +#define vsetvlmax_e16mf4() vsetvlimax(1, 6) +#define vsetvlmax_e16mf2() vsetvlimax(1, 7) +#define vsetvlmax_e16m1() vsetvlimax(1, 0) +#define vsetvlmax_e16m2() vsetvlimax(1, 1) +#define vsetvlmax_e16m4() vsetvlimax(1, 2) +#define vsetvlmax_e16m8() vsetvlimax(1, 3) + +#define vsetvlmax_e32mf2() vsetvlimax(2, 7) +#define vsetvlmax_e32m1() vsetvlimax(2, 0) +#define vsetvlmax_e32m2() vsetvlimax(2, 1) +#define vsetvlmax_e32m4() vsetvlimax(2, 2) +#define vsetvlmax_e32m8() vsetvlimax(2, 3) + +#define vsetvlmax_e64m1() vsetvlimax(3, 0) +#define vsetvlmax_e64m2() vsetvlimax(3, 1) +#define vsetvlmax_e64m4() vsetvlimax(3, 2) +#define vsetvlmax_e64m8() vsetvlimax(3, 3) }] in def vsetvlimax : RVVBuiltin<"", "zKzKz", "i">; 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 @@ -210,6 +210,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/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10002,6 +10002,9 @@ void ActOnPragmaFPExceptions(SourceLocation Loc, LangOptions::FPExceptionModeKind); + /// Called on well formed '\#pragma riscv intrinsic'. + void ActOnPragmaRISCVIntrinsic(); + /// Called to set constant rounding mode for floating point operations. void setRoundingMode(SourceLocation Loc, llvm::RoundingMode); diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp --- a/clang/lib/Basic/Builtins.cpp +++ b/clang/lib/Basic/Builtins.cpp @@ -18,13 +18,15 @@ using namespace clang; static const Builtin::Info BuiltinInfo[] = { - { "not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES,nullptr}, + {"not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES, + nullptr, nullptr, Builtin::ALWAYS_KIND}, #define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, + {#ID, TYPE, ATTRS, nullptr, \ + ALL_LANGUAGES, nullptr, nullptr, Builtin::ALWAYS_KIND}, #define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \ - { #ID, TYPE, ATTRS, nullptr, LANGS, nullptr }, + {#ID, TYPE, ATTRS, nullptr, LANGS, nullptr, nullptr, Builtin::ALWAYS_KIND}, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \ - { #ID, TYPE, ATTRS, HEADER, LANGS, nullptr }, + {#ID, TYPE, ATTRS, HEADER, LANGS, nullptr, nullptr, Builtin::ALWAYS_KIND}, #include "clang/Basic/Builtins.def" }; @@ -56,7 +58,8 @@ } bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo, - const LangOptions &LangOpts) { + const LangOptions &LangOpts, + BuiltinKind Kind) { bool BuiltinsUnsupported = (LangOpts.NoBuiltin || LangOpts.isNoBuiltinFunc(BuiltinInfo.Name)) && strchr(BuiltinInfo.Attributes, 'f'); @@ -78,10 +81,11 @@ bool CUDAUnsupported = !LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG; bool CPlusPlusUnsupported = !LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG; + bool SupportedKind = BuiltinInfo.Kind == Kind; return !BuiltinsUnsupported && !MathBuiltinsUnsupported && !OclCUnsupported && !OclC1Unsupported && !OclC2Unsupported && !OpenMPUnsupported && !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported && - !CPlusPlusUnsupported && !CUDAUnsupported; + !CPlusPlusUnsupported && !CUDAUnsupported && SupportedKind; } /// initializeBuiltins - Mark the identifiers for all the builtins with their @@ -91,13 +95,13 @@ const LangOptions& LangOpts) { // Step #1: mark all target-independent builtins with their ID's. for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) - if (builtinIsSupported(BuiltinInfo[i], LangOpts)) { + if (builtinIsSupported(BuiltinInfo[i], LangOpts, Builtin::ALWAYS_KIND)) { Table.get(BuiltinInfo[i].Name).setBuiltinID(i); } // Step #2: Register target-specific builtins. for (unsigned i = 0, e = TSRecords.size(); i != e; ++i) - if (builtinIsSupported(TSRecords[i], LangOpts)) + if (builtinIsSupported(TSRecords[i], LangOpts, Builtin::ALWAYS_KIND)) Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin); // Step #3: Register target-specific builtins for AuxTarget. @@ -106,6 +110,23 @@ .setBuiltinID(i + Builtin::FirstTSBuiltin + TSRecords.size()); } +void Builtin::Context::initializeTargetBuiltins(IdentifierTable &Table, + const LangOptions &LangOpts, + BuiltinKind Kind) { + for (unsigned i = 0, e = TSRecords.size(); i != e; ++i) + if (builtinIsSupported(TSRecords[i], LangOpts, Kind)) + Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin); +} + +void Builtin::Context::initializeTargetOverloadBuiltins( + Sema &S, RegisterOverloadBuiltinFunc Func, const LangOptions &LangOpts, + BuiltinKind Kind) { + for (unsigned i = 0, e = TSRecords.size(); i != e; ++i) { + if (builtinIsSupported(TSRecords[i], LangOpts, Kind) && + TSRecords[i].Overload) + Func(S, TSRecords[i], i + Builtin::FirstTSBuiltin); + } +} unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const { const char *WidthPos = ::strchr(getRecord(ID).Attributes, 'V'); if (!WidthPos) diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -228,9 +228,16 @@ const Builtin::Info RISCVTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ - {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, + {#ID, TYPE, ATTRS, nullptr, \ + ALL_LANGUAGES, nullptr, nullptr, Builtin::ALWAYS_KIND}, #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ - {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, + {#ID, TYPE, ATTRS, nullptr, \ + ALL_LANGUAGES, FEATURE, nullptr, Builtin::ALWAYS_KIND}, +#define RISCVV_BUILTIN(ID, TYPE, ATTRS, OVERLOAD) \ + {#ID, TYPE, \ + ATTRS, nullptr, \ + ALL_LANGUAGES, "experimental-v", \ + OVERLOAD, Builtin::RISCV_VECTOR_KIND}, #include "clang/Basic/BuiltinsRISCV.def" }; 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 @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/PragmaKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -294,6 +295,15 @@ Token &FirstToken) override; }; +struct PragmaRISCVHandler : public PragmaHandler { + PragmaRISCVHandler(Sema &S) : PragmaHandler("riscv"), Actions(S) {} + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &FirstToken) override; + +private: + Sema &Actions; +}; + void markAsReinjectedForRelexing(llvm::MutableArrayRef Toks) { for (auto &T : Toks) T.setFlag(clang::Token::IsReinjected); @@ -431,6 +441,11 @@ MaxTokensTotalPragmaHandler = std::make_unique(); PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get()); + + if (getTargetInfo().getTriple().isRISCV()) { + RISCVPragmaHandler = std::make_unique(Actions); + PP.AddPragmaHandler(RISCVPragmaHandler.get()); + } } void Parser::resetPragmaHandlers() { @@ -549,6 +564,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(...) @@ -3439,6 +3459,41 @@ << "intrinsic"; } +// #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; + } +#if 0 + // Generate the annotated pragma token. + auto TokenArray = std::make_unique(1); + TokenArray[0].startToken(); + TokenArray[0].setKind(tok::annot_pragma_riscv); + TokenArray[0].setLocation(FirstToken.getLocation()); + TokenArray[0].setAnnotationEndLoc(FirstToken.getLocation()); + + PP.EnterTokenStream(std::move(TokenArray), 1, + /*DisableMacroExpansion=*/false, /*IsReinject=*/false); +#endif + + Actions.ActOnPragmaRISCVIntrinsic(); +} + // #pragma optimize("gsty", on|off) void PragmaMSOptimizeHandler::HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -51,6 +51,7 @@ SemaOpenMP.cpp SemaOverload.cpp SemaPseudoObject.cpp + SemaRISCV.cpp SemaStmt.cpp SemaStmtAsm.cpp SemaStmtAttr.cpp diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3472,10 +3472,10 @@ return true; switch (BuiltinID) { - case RISCV::BI__builtin_rvv_vsetvli: + case RISCV::BIvsetvli: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3) || CheckRISCVLMUL(TheCall, 2); - case RISCV::BI__builtin_rvv_vsetvlimax: + case RISCV::BIvsetvlimax: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || CheckRISCVLMUL(TheCall, 1); } diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -0,0 +1,34 @@ +//===--- SemaRISCV.cpp - Semantic Analysis for RISC-V pragmas -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements semantic analysis for RISC-V pragmas. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Builtins.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/Sema.h" +using namespace clang; + +void Sema::ActOnPragmaRISCVIntrinsic() { + PP.getBuiltinInfo().initializeTargetBuiltins( + PP.getIdentifierTable(), PP.getLangOpts(), Builtin::RISCV_VECTOR_KIND); + Builtin::RegisterOverloadBuiltinFunc F = [](Sema &S, const Builtin::Info &BI, + unsigned ID) { + auto &OverloadII = S.PP.getIdentifierTable().get(BI.Overload); + auto &II = S.PP.getIdentifierTable().get(BI.Name); + SourceLocation Loc; + auto *FDecl = + S.LazilyCreateBuiltin(&OverloadII, ID, S.getCurScope(), false, Loc); + FDecl->addAttr(OverloadableAttr::CreateImplicit(S.Context)); + FDecl->addAttr(BuiltinAliasAttr::CreateImplicit(S.Context, &II)); + }; + + PP.getBuiltinInfo().initializeTargetOverloadBuiltins( + *this, F, PP.getLangOpts(), Builtin::RISCV_VECTOR_KIND); +} diff --git a/clang/test/CodeGen/RISCV/riscv-attr-builtin-alias.c b/clang/test/CodeGen/RISCV/riscv-attr-builtin-alias.c --- a/clang/test/CodeGen/RISCV/riscv-attr-builtin-alias.c +++ b/clang/test/CodeGen/RISCV/riscv-attr-builtin-alias.c @@ -10,7 +10,7 @@ static inline __attribute__((__always_inline__, __nodebug__)) __rvv_generic -__attribute__((clang_builtin_alias(__builtin_rvv_vadd_vv_i8m1))) +__attribute__((clang_builtin_alias(vadd_vv_i8m1))) vint8m1_t vadd_generic (vint8m1_t op0, vint8m1_t op1, size_t op2); // CHECK-LABEL: @test( diff --git a/clang/test/CodeGen/RISCV/rvv_errors.c b/clang/test/CodeGen/RISCV/rvv_errors.c --- a/clang/test/CodeGen/RISCV/rvv_errors.c +++ b/clang/test/CodeGen/RISCV/rvv_errors.c @@ -1,10 +1,11 @@ // RUN: %clang_cc1 %s -triple=riscv64 -target-feature +experimental-v -fsyntax-only -verify +#pragma riscv intrinsic vector void test() { - __builtin_rvv_vsetvli(1, 7, 0); // expected-error {{argument value 7 is outside the valid range [0, 3]}} - __builtin_rvv_vsetvlimax(-1, 0); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 3]}} - __builtin_rvv_vsetvli(1, 0, 4); // expected-error {{LMUL argument must be in the range [0,3] or [5,7]}} - __builtin_rvv_vsetvlimax(0, 4); // expected-error {{LMUL argument must be in the range [0,3] or [5,7]}} - __builtin_rvv_vsetvli(1, 0, 8); // expected-error {{LMUL argument must be in the range [0,3] or [5,7]}} - __builtin_rvv_vsetvlimax(0, -1); // expected-error {{LMUL argument must be in the range [0,3] or [5,7]}} + vsetvli(1, 7, 0); // expected-error {{argument value 7 is outside the valid range [0, 3]}} + vsetvlimax(-1, 0); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 3]}} + vsetvli(1, 0, 4); // expected-error {{LMUL argument must be in the range [0,3] or [5,7]}} + vsetvlimax(0, 4); // expected-error {{LMUL argument must be in the range [0,3] or [5,7]}} + vsetvli(1, 0, 8); // expected-error {{LMUL argument must be in the range [0,3] or [5,7]}} + vsetvlimax(0, -1); // expected-error {{LMUL argument must be in the range [0,3] or [5,7]}} } 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 @@ -197,9 +197,6 @@ // 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 { @@ -836,36 +833,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 //===----------------------------------------------------------------------===// @@ -897,6 +864,7 @@ OS << "#ifdef __cplusplus\n"; OS << "extern \"C\" {\n"; OS << "#endif\n\n"; + OS << "#pragma riscv intrinsic vector\n\n"; std::vector> Defs; createRVVIntrinsics(Defs); @@ -953,53 +921,47 @@ } OS << "#endif\n\n"; - // The same extension include in the same arch guard marco. - std::stable_sort(Defs.begin(), Defs.end(), - [](const std::unique_ptr &A, - const std::unique_ptr &B) { - 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"; OS << "#endif // __RISCV_VECTOR_H\n"; } +struct OverloadTable { + SmallVector Target; + bool HasSideEffects; +}; + void RVVEmitter::createBuiltins(raw_ostream &OS) { std::vector> Defs; createRVVIntrinsics(Defs); OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; - OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " + OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS, OVERLOAD) TARGET_BUILTIN(ID, " + "TYPE, " + "ATTRS, \"experimental-v\")\n"; + OS << "#endif\n"; + OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_OVERLOAD_BUILTIN)\n"; + OS << "#define RISCVV_OVERLOAD_BUILTIN(ID, TYPE, ATTRS, OVERLOAD_LIST) " + "TARGET_BUILTIN(ID, TYPE, " "ATTRS, \"experimental-v\")\n"; OS << "#endif\n"; for (auto &Def : Defs) { - OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getName() << ",\"" - << Def->getBuiltinTypeStr() << "\", "; + OS << "RISCVV_BUILTIN(" << Def->getName() << ",\"" + << Def->getBuiltinTypeStr() << "\", \""; if (!Def->hasSideEffects()) - OS << "\"n\")\n"; + OS << "n"; + + OS << "\", "; + if (!Def->isMask() && !Def->hasNoMaskedOverloaded()) + OS << "nullptr"; else - OS << "\"\")\n"; + OS << "\"" << Def->getMangledName() << "\""; + OS << ")\n"; } + OS << "#undef RISCVV_BUILTIN\n"; } @@ -1022,7 +984,7 @@ PrevDef->emitCodeGenSwitchBody(OS); } PrevDef = Def.get(); - OS << "case RISCV::BI__builtin_rvv_" << Def->getName() << ":\n"; + OS << "case RISCV::BI" << Def->getName() << ":\n"; } Defs.back()->emitCodeGenSwitchBody(OS); OS << "\n";