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,9 @@ clang_tablegen(riscv_vector_builtin_cg.inc -gen-riscv-vector-builtin-codegen SOURCE riscv_vector.td TARGET ClangRISCVVectorBuiltinCG) +clang_tablegen(riscv_vector_intrinsic_info.inc -gen-riscv-vector-intrinsic-info + SOURCE riscv_vector.td + TARGET ClangRISCVVectorIntrinsicInfo) +clang_tablegen(riscv_vector_intrinsic_overload_info.inc -gen-riscv-vector-intrinsic-overload-info + SOURCE riscv_vector.td + TARGET ClangRISCVVectorIntrinsicOverloadInfo) 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 @@ -878,6 +878,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 @@ -211,6 +211,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 @@ -10028,6 +10028,9 @@ void ActOnPragmaFPExceptions(SourceLocation Loc, LangOptions::FPExceptionModeKind); + /// Called on well formed '\#pragma riscv intrinsic'. + void ActOnPragmaRISCVIntrinsic(SourceLocation Loc); + /// Called to set constant rounding mode for floating point operations. void setRoundingMode(SourceLocation Loc, llvm::RoundingMode); 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 @@ -294,6 +294,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 +440,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 +563,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 +3458,30 @@ << "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; + } + + Actions.ActOnPragmaRISCVIntrinsic(FirstToken.getLocation()); +} + // #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/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -0,0 +1,86 @@ +//===--- 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/Basic/TargetBuiltins.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/Sema.h" +using namespace clang; + +enum Features { + Feature_F = 1 << 0, + Feature_D = 1 << 1, + Feature_ZFH = 1 << 2, + Feature_ZVAMO = 1 << 3, +}; + +struct RVVIntrinsicInfo { + const char *TargetName; + unsigned TargetBuiltinID; + unsigned RequireFeatures; +}; + +struct RVVIntrinsicOverloadInfo { + const char *TargetName; + const char *OverloadName; + unsigned TargetBuiltinID; + unsigned RequireFeatures; +}; + +static const RVVIntrinsicInfo RVVIntrinsicInfos[] = { +#include "clang/Basic/riscv_vector_intrinsic_info.inc" +}; + +static const RVVIntrinsicOverloadInfo RVVIntrinsicOverloadInfos[] = { +#include "clang/Basic/riscv_vector_intrinsic_overload_info.inc" +}; + +void Sema::ActOnPragmaRISCVIntrinsic(SourceLocation Loc) { + auto &TI = Context.getTargetInfo(); + bool HasF = TI.hasFeature("f"); + bool HasD = TI.hasFeature("d"); + bool HasZvamo = TI.hasFeature("experimental-zvamo"); + bool HasZfh = TI.hasFeature("experimental-zfh"); + unsigned Features = 0; + if (HasF) + Features |= Feature_F; + if (HasD) + Features |= Feature_D; + if (HasZfh) + Features |= Feature_ZFH; + if (HasZvamo) + Features |= Feature_ZVAMO; + + for (auto InstrInfo : RVVIntrinsicInfos) { + // Check feature requirement. + if ((InstrInfo.RequireFeatures & Features) != InstrInfo.RequireFeatures) + continue; + + PP.getIdentifierTable() + .get(InstrInfo.TargetName) + .setBuiltinID(InstrInfo.TargetBuiltinID); + } + + for (auto InstrInfo : RVVIntrinsicOverloadInfos) { + // Check feature requirement. + if ((InstrInfo.RequireFeatures & Features) != InstrInfo.RequireFeatures) + continue; + + auto &OverloadII = PP.getIdentifierTable().get(InstrInfo.OverloadName); + auto &II = PP.getIdentifierTable().get(InstrInfo.TargetName); + auto *FuncDecl = LazilyCreateBuiltin(&OverloadII, InstrInfo.TargetBuiltinID, + getCurScope(), false, Loc); + FuncDecl->addAttr(OverloadableAttr::CreateImplicit(Context)); + FuncDecl->addAttr(BuiltinAliasAttr::CreateImplicit(Context, &II)); + } +} 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 @@ -194,12 +194,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 { @@ -222,6 +216,12 @@ /// Emit all the information needed to map builtin -> LLVM IR intrinsic. void createCodeGen(raw_ostream &o); + /// Emit all the intrinsic info for `#pragma riscv vector intrinsic`. + void createIntrinsicInfo(raw_ostream &o); + + /// Emit all the intrinsic overload info for `#pragma riscv vector intrinsic`. + void createIntrinsicOverloadInfo(raw_ostream &o); + std::string getSuffixStr(char Type, int Log2LMUL, StringRef Prototypes); private: @@ -235,15 +235,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, @@ -836,36 +827,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 +858,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); @@ -960,24 +922,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"; @@ -1169,41 +1115,46 @@ 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 << "Feature_F"; if (Extents & RISCVExtension::D) - OS << LS << "defined(__riscv_d)"; + OS << LS << "Feature_D"; if (Extents & RISCVExtension::Zfh) - OS << LS << "defined(__riscv_zfh)"; + OS << LS << "Feature_ZFH"; if (Extents & RISCVExtension::Zvamo) - OS << LS << "defined(__riscv_zvamo)"; - OS << "\n"; - return true; + OS << LS << "Feature_ZVAMO"; +} + +void RVVEmitter::createIntrinsicInfo(raw_ostream &OS) { + std::vector> Defs; + createRVVIntrinsics(Defs); + for (auto &Def : Defs) { + OS << " {\"" << Def->getName() << "\", "; + OS << "RISCV::BI__builtin_rvv_" << Def->getName() << ", "; + emitFeatureCheckStr(Def->getRISCVExtensions(), OS); + OS << "},\n"; + } +} + +void RVVEmitter::createIntrinsicOverloadInfo(raw_ostream &OS) { + std::vector> Defs; + createRVVIntrinsics(Defs); + 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"; + } } namespace clang { @@ -1219,4 +1170,12 @@ RVVEmitter(Records).createCodeGen(OS); } +void EmitRVVIntrinsicInfo(RecordKeeper &Records, raw_ostream &OS) { + RVVEmitter(Records).createIntrinsicInfo(OS); +} + +void EmitRVVIntrinsicOverloadInfo(RecordKeeper &Records, raw_ostream &OS) { + RVVEmitter(Records).createIntrinsicOverloadInfo(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 @@ -86,6 +86,8 @@ GenRISCVVectorHeader, GenRISCVVectorBuiltins, GenRISCVVectorBuiltinCG, + GenRISCVVectorIntrinsicInfo, + GenRISCVVectorIntrinsicOverloadInfo, GenAttrDocs, GenDiagDocs, GenOptDocs, @@ -237,6 +239,13 @@ "Generate riscv_vector_builtins.inc for clang"), clEnumValN(GenRISCVVectorBuiltinCG, "gen-riscv-vector-builtin-codegen", "Generate riscv_vector_builtin_cg.inc for clang"), + clEnumValN(GenRISCVVectorIntrinsicInfo, + "gen-riscv-vector-intrinsic-info", + "Generate riscv_vector_intrinsic_info.inc for clang."), + clEnumValN( + GenRISCVVectorIntrinsicOverloadInfo, + "gen-riscv-vector-intrinsic-overload-info", + "Generate riscv_vector_intrinsic_overload_info.inc for clang."), clEnumValN(GenAttrDocs, "gen-attr-docs", "Generate attribute documentation"), clEnumValN(GenDiagDocs, "gen-diag-docs", @@ -446,6 +455,12 @@ case GenRISCVVectorBuiltinCG: EmitRVVBuiltinCG(Records, OS); break; + case GenRISCVVectorIntrinsicInfo: + EmitRVVIntrinsicInfo(Records, OS); + break; + case GenRISCVVectorIntrinsicOverloadInfo: + EmitRVVIntrinsicOverloadInfo(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 @@ -109,6 +109,9 @@ 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 EmitRVVIntrinsicInfo(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); +void EmitRVVIntrinsicOverloadInfo(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,14 @@ Generate ``riscv_vector_builtin_cg.inc`` for Clang. +.. option:: -gen-riscv-vector-intrinsic-info + + Generate ``riscv_vector_intrinsic_info.inc`` for Clang. + +.. option:: -gen-riscv-vector-intrinsic-overload-info + + Generate ``riscv_vector_intrinsic_overload_info.inc`` for Clang. + .. option:: -gen-attr-docs Generate attribute documentation.