rG7a5cb15ea6fa
source link: https://reviews.llvm.org/rG7a5cb15ea6fa
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
- Restricted Project
- Restricted Project
[RISCV] Lazily add RVV C intrinsics.
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.
Experimental Results
TL;DR:
- Binary size of clang increase ~200k, which is +0.07% for debug build and +0.13% for release build.
- Single file compilation speed up ~33x for debug build and ~8.5x for release build
- Regression time reduce ~10% (ninja check-all, enable all targets)
Header size change
| size | LoC | ------------------------------ Before | 4,434,725 | 69,749 | After | 6,140 | 162 |
Single File Compilation Time
Testcase:
#include <riscv_vector.h> vint32m1_t test_vadd_vv_vfloat32m1_t(vint32m1_t op1, vint32m1_t op2, size_t vl) { return vadd(op1, op2, vl); }
Debug build:
Before:
real 0m19.352s user 0m19.252s sys 0m0.092s
After:
real 0m0.576s user 0m0.552s sys 0m0.024s
~33x speed up for debug build
Release build:
Before:
real 0m0.773s user 0m0.741s sys 0m0.032s
After:
real 0m0.092s user 0m0.080s sys 0m0.012s
~8.5x speed up for release build
Regression time
Note: the failed case is tools/llvm-debuginfod-find/debuginfod.test which is unrelated to this patch.
Debug build
Before:
Testing Time: 1358.38s Skipped : 11 Unsupported : 446 Passed : 75767 Expectedly Failed: 190 Failed : 1
After
Testing Time: 1220.29s Skipped : 11 Unsupported : 446 Passed : 75767 Expectedly Failed: 190 Failed : 1
Release build
Before:
Testing Time: 381.98s Skipped : 12 Unsupported : 1407 Passed : 74765 Expectedly Failed: 176 Failed : 1
After:
Testing Time: 346.25s Skipped : 12 Unsupported : 1407 Passed : 74765 Expectedly Failed: 176 Failed : 1
Binary size of clang
Debug build
Before
text data bss dec hex filename 335261851 12726004 552812 348540667 14c64efb bin/clang
After
text data bss dec hex filename 335442803 12798708 552940 348794451 14ca2e53 bin/clang
+253K, +0.07% code size
Release build
Before
text data bss dec hex filename 144123975 8374648 483140 152981763 91e5103 bin/clang
After
text data bss dec hex filename 144255762 8447296 483268 153186326 9217016 bin/clang
+204K, +0.13%
Authored-by: Kito Cheng <[email protected]>
Co-Authored-by: Hsiangkai Wang <[email protected]>
Reviewed By: khchen, aaron.ballman
Differential Revision: https://reviews.llvm.org/D111617
clang/include/clang/Basic/CMakeLists.txt
Show First 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||
SOURCE arm_cde.td | |||
TARGET ClangARMCdeBuiltinAliases) | |||
clang_tablegen(riscv_vector_builtins.inc -gen-riscv-vector-builtins | |||
SOURCE riscv_vector.td | |||
TARGET ClangRISCVVectorBuiltins) | |||
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) |
clang/include/clang/Basic/TokenKinds.def
Show First 20 Lines • Show All 902 Lines • ▼ Show 20 Lines | |||
// handles #pragma loop ... directives. | |||
PRAGMA_ANNOTATION(pragma_loop_hint) | |||
PRAGMA_ANNOTATION(pragma_fp) | |||
// Annotation for the attribute pragma directives - #pragma clang attribute ... | |||
PRAGMA_ANNOTATION(pragma_attribute) | |||
+ // Annotation for the riscv pragma directives - #pragma clang riscv intrinsic ... | |||
+ PRAGMA_ANNOTATION(pragma_riscv) | |||
+ | |||
// Annotations for module import translated from #include etc. | |||
ANNOTATION(module_include) | |||
ANNOTATION(module_begin) | |||
ANNOTATION(module_end) | |||
// Annotation for a header_name token that has been looked up and transformed | |||
// into the name of a header unit. | |||
ANNOTATION(header_unit) | |||
Show All 22 Lines |
clang/include/clang/Parse/Parser.h
Show First 20 Lines • Show All 209 Lines • ▼ Show 20 Lines | |||
std::unique_ptr<PragmaHandler> FPHandler; | |||
std::unique_ptr<PragmaHandler> STDCFenvAccessHandler; | |||
std::unique_ptr<PragmaHandler> STDCFenvRoundHandler; | |||
std::unique_ptr<PragmaHandler> STDCCXLIMITHandler; | |||
std::unique_ptr<PragmaHandler> STDCUnknownHandler; | |||
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; | |||
/// Whether the '>' token acts as an operator or not. This will be | |||
/// true except when we are parsing an expression within a C++ | |||
/// template argument list, where the '>' closes the template | |||
/// argument list. | |||
bool GreaterThanIsOperator; | |||
▲ Show 20 Lines • Show All 3,280 Lines • Show Last 20 Lines |
clang/include/clang/Sema/RISCVIntrinsicManager.h
- This file was added.
+ //===- RISCVIntrinsicManager.h - RISC-V Intrinsic Handler -------*- C++ -*-===// | |||
+ // | |||
+ // 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 | |||
+ // | |||
+ //===----------------------------------------------------------------------===// | |||
+ // | |||
+ // This file defines the RISCVIntrinsicManager, which handles RISC-V vector | |||
+ // intrinsic functions. | |||
+ // | |||
+ //===----------------------------------------------------------------------===// | |||
+ | |||
+ #ifndef LLVM_CLANG_SEMA_RISCVINTRINSICMANAGER_H | |||
+ #define LLVM_CLANG_SEMA_RISCVINTRINSICMANAGER_H | |||
+ | |||
+ namespace clang { | |||
+ class Sema; | |||
+ class LookupResult; | |||
+ class IdentifierInfo; | |||
+ class Preprocessor; | |||
+ | |||
+ namespace sema { | |||
+ class RISCVIntrinsicManager { | |||
+ public: | |||
+ virtual ~RISCVIntrinsicManager() = default; | |||
+ | |||
+ // Create RISC-V intrinsic and insert into symbol table and return true if | |||
+ // found, otherwise return false. | |||
+ virtual bool CreateIntrinsicIfFound(LookupResult &LR, IdentifierInfo *II, | |||
+ Preprocessor &PP) = 0; | |||
+ }; | |||
+ } // end namespace sema | |||
+ } // end namespace clang | |||
+ | |||
+ #endif |
clang/include/clang/Sema/Sema.h
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 220 Lines • ▼ Show 20 Lines | |||
class CapturedRegionScopeInfo; | |||
class CapturingScopeInfo; | |||
class CompoundScopeInfo; | |||
class DelayedDiagnostic; | |||
class DelayedDiagnosticPool; | |||
class FunctionScopeInfo; | |||
class LambdaScopeInfo; | |||
class PossiblyUnreachableDiag; | |||
+ class RISCVIntrinsicManager; | |||
class SemaPPCallbacks; | |||
class TemplateDeductionInfo; | |||
} | |||
namespace threadSafety { | |||
class BeforeSet; | |||
void threadSafetyCleanup(BeforeSet* Cache); | |||
} | |||
▲ Show 20 Lines • Show All 1,345 Lines • ▼ Show 20 Lines | |||
bool WarnedStackExhausted = false; | |||
/// Increment when we find a reference; decrement when we find an ignored | |||
/// assignment. Ultimately the value is 0 if every reference is an ignored | |||
/// assignment. | |||
llvm::DenseMap<const VarDecl *, int> RefsMinusAssignments; | |||
+ /// Indicate RISC-V vector builtin functions enabled or not. | |||
+ bool DeclareRISCVVBuiltins = false; | |||
+ | |||
private: | |||
+ std::unique_ptr<sema::RISCVIntrinsicManager> RVIntrinsicManager; | |||
+ | |||
Optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo; | |||
bool WarnedDarwinSDKInfoMissing = false; | |||
public: | |||
Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, | |||
TranslationUnitKind TUKind = TU_Complete, | |||
CodeCompleteConsumer *CompletionConsumer = nullptr); | |||
▲ Show 20 Lines • Show All 11,986 Lines • ▼ Show 20 Lines | |||
}; | |||
template <> | |||
void Sema::PragmaStack<Sema::AlignPackInfo>::Act(SourceLocation PragmaLocation, | |||
PragmaMsStackAction Action, | |||
llvm::StringRef StackSlotLabel, | |||
AlignPackInfo Value); | |||
+ std::unique_ptr<sema::RISCVIntrinsicManager> | |||
+ CreateRISCVIntrinsicManager(Sema &S); | |||
} // end namespace clang | |||
namespace llvm { | |||
// Hash a FunctionDeclAndLoc by looking at both its FunctionDecl and its | |||
// SourceLocation. | |||
template <> struct DenseMapInfo<clang::Sema::FunctionDeclAndLoc> { | |||
using FunctionDeclAndLoc = clang::Sema::FunctionDeclAndLoc; | |||
using FDBaseInfo = DenseMapInfo<clang::CanonicalDeclPtr<clang::FunctionDecl>>; | |||
Show All 22 Lines |
clang/include/clang/Support/RISCVVIntrinsicUtils.h
Show All 12 Lines | |||
#include "llvm/ADT/BitmaskEnum.h" | |||
#include "llvm/ADT/Optional.h" | |||
#include "llvm/ADT/SmallVector.h" | |||
#include "llvm/ADT/StringRef.h" | |||
#include <cstdint> | |||
#include <string> | |||
#include <vector> | |||
+ namespace llvm { | |||
+ class raw_ostream; | |||
+ } // end namespace llvm | |||
+ | |||
namespace clang { | |||
namespace RISCV { | |||
using VScaleVal = llvm::Optional<unsigned>; | |||
// Modifier for vector type. | |||
enum class VectorTypeModifier : uint8_t { | |||
NoModifier, | |||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | |||
constexpr PrototypeDescriptor(uint8_t PT, uint8_t VTM, uint8_t TM) | |||
: PT(PT), VTM(VTM), TM(TM) {} | |||
uint8_t PT = static_cast<uint8_t>(BaseTypeModifier::Invalid); | |||
uint8_t VTM = static_cast<uint8_t>(VectorTypeModifier::NoModifier); | |||
uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier); | |||
bool operator!=(const PrototypeDescriptor &PD) const { | |||
- return PD.PT != PT || PD.VTM != VTM || PD.TM != TM; | |||
+ return !(*this == PD); | |||
} | |||
- bool operator>(const PrototypeDescriptor &PD) const { | |||
- return !(PD.PT <= PT && PD.VTM <= VTM && PD.TM <= TM); | |||
+ bool operator==(const PrototypeDescriptor &PD) const { | |||
+ return PD.PT == PT && PD.VTM == VTM && PD.TM == TM; | |||
+ } | |||
+ bool operator<(const PrototypeDescriptor &PD) const { | |||
+ return std::tie(PT, VTM, TM) < std::tie(PD.PT, PD.VTM, PD.TM); | |||
} | |||
- | |||
static const PrototypeDescriptor Mask; | |||
static const PrototypeDescriptor Vector; | |||
static const PrototypeDescriptor VL; | |||
static llvm::Optional<PrototypeDescriptor> | |||
parsePrototypeDescriptor(llvm::StringRef PrototypeStr); | |||
}; | |||
llvm::SmallVector<PrototypeDescriptor> | |||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | |||
return ScalarType == ScalarTypeKind::SignedInteger; | |||
} | |||
bool isFloatVector(unsigned Width) const { | |||
return isVector() && isFloat() && ElementBitwidth == Width; | |||
} | |||
bool isFloat(unsigned Width) const { | |||
return isFloat() && ElementBitwidth == Width; | |||
} | |||
- | |||
+ bool isConstant() const { return IsConstant; } | |||
bool isPointer() const { return IsPointer; } | |||
+ unsigned getElementBitwidth() const { return ElementBitwidth; } | |||
+ | |||
+ ScalarTypeKind getScalarType() const { return ScalarType; } | |||
+ VScaleVal getScale() const { return Scale; } | |||
private: | |||
// Verify RVV vector type and set Valid. | |||
bool verifyType() const; | |||
// Creates a type based on basic types of TypeRange | |||
void applyBasicType(); | |||
Show All 21 Lines | |||
/// have illegal RVVType. | |||
static llvm::Optional<RVVTypes> | |||
computeTypes(BasicType BT, int Log2LMUL, unsigned NF, | |||
llvm::ArrayRef<PrototypeDescriptor> Prototype); | |||
static llvm::Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, | |||
PrototypeDescriptor Proto); | |||
}; | |||
- using RISCVPredefinedMacroT = uint8_t; | |||
- | |||
- enum RISCVPredefinedMacro : RISCVPredefinedMacroT { | |||
- Basic = 0, | |||
- V = 1 << 1, | |||
- Zvfh = 1 << 2, | |||
- RV64 = 1 << 3, | |||
- VectorMaxELen64 = 1 << 4, | |||
- VectorMaxELenFp32 = 1 << 5, | |||
- VectorMaxELenFp64 = 1 << 6, | |||
- }; | |||
- | |||
enum PolicyScheme : uint8_t { | |||
SchemeNone, | |||
HasPassthruOperand, | |||
HasPolicyOperand, | |||
}; | |||
// TODO refactor RVVIntrinsic class design after support all intrinsic | |||
// combination. This represents an instantiation of an intrinsic with a | |||
Show All 11 Lines | |||
bool HasUnMaskedOverloaded; | |||
bool HasBuiltinAlias; | |||
std::string ManualCodegen; | |||
RVVTypePtr OutputType; // Builtin output type | |||
RVVTypes InputTypes; // Builtin input types | |||
// The types we use to obtain the specific LLVM intrinsic. They are index of | |||
// InputTypes. -1 means the return type. | |||
std::vector<int64_t> IntrinsicTypes; | |||
- RISCVPredefinedMacroT RISCVPredefinedMacros = 0; | |||
unsigned NF = 1; | |||
public: | |||
RVVIntrinsic(llvm::StringRef Name, llvm::StringRef Suffix, | |||
llvm::StringRef OverloadedName, llvm::StringRef OverloadedSuffix, | |||
llvm::StringRef IRName, bool IsMasked, bool HasMaskedOffOperand, | |||
bool HasVL, PolicyScheme Scheme, bool HasUnMaskedOverloaded, | |||
bool HasBuiltinAlias, llvm::StringRef ManualCodegen, | |||
Show All 14 Lines | |||
bool hasPolicyOperand() const { return Scheme == HasPolicyOperand; } | |||
bool hasUnMaskedOverloaded() const { return HasUnMaskedOverloaded; } | |||
bool hasBuiltinAlias() const { return HasBuiltinAlias; } | |||
bool hasManualCodegen() const { return !ManualCodegen.empty(); } | |||
bool isMasked() const { return IsMasked; } | |||
llvm::StringRef getIRName() const { return IRName; } | |||
llvm::StringRef getManualCodegen() const { return ManualCodegen; } | |||
PolicyScheme getPolicyScheme() const { return Scheme; } | |||
- RISCVPredefinedMacroT getRISCVPredefinedMacros() const { | |||
- return RISCVPredefinedMacros; | |||
- } | |||
unsigned getNF() const { return NF; } | |||
const std::vector<int64_t> &getIntrinsicTypes() const { | |||
return IntrinsicTypes; | |||
} | |||
// Return the type string for a BUILTIN() macro in Builtins.def. | |||
std::string getBuiltinTypeStr() const; | |||
static std::string | |||
getSuffixStr(BasicType Type, int Log2LMUL, | |||
llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors); | |||
}; | |||
+ // RVVRequire should be sync'ed with target features, but only | |||
+ // required features used in riscv_vector.td. | |||
+ enum RVVRequire : uint8_t { | |||
+ RVV_REQ_None = 0, | |||
+ RVV_REQ_RV64 = 1 << 0, | |||
+ RVV_REQ_FullMultiply = 1 << 1, | |||
+ | |||
+ LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_FullMultiply) | |||
+ }; | |||
+ | |||
+ // Raw RVV intrinsic info, used to expand later. | |||
+ // This struct is highly compact for minimized code size. | |||
+ struct RVVIntrinsicRecord { | |||
+ // Intrinsic name, e.g. vadd_vv | |||
+ const char *Name; | |||
+ | |||
+ // Overloaded intrinsic name, could be empty if it can be computed from Name. | |||
+ // e.g. vadd | |||
+ const char *OverloadedName; | |||
+ | |||
+ // Prototype for this intrinsic, index of RVVSignatureTable. | |||
+ uint16_t PrototypeIndex; | |||
+ | |||
+ // Prototype for masked intrinsic, index of RVVSignatureTable. | |||
+ uint16_t MaskedPrototypeIndex; | |||
+ | |||
+ // Suffix of intrinsic name, index of RVVSignatureTable. | |||
+ uint16_t SuffixIndex; | |||
+ | |||
+ // Suffix of overloaded intrinsic name, index of RVVSignatureTable. | |||
+ uint16_t OverloadedSuffixIndex; | |||
+ | |||
+ // Length of the prototype. | |||
+ uint8_t PrototypeLength; | |||
+ | |||
+ // Length of prototype of masked intrinsic. | |||
+ uint8_t MaskedPrototypeLength; | |||
+ | |||
+ // Length of intrinsic name suffix. | |||
+ uint8_t SuffixLength; | |||
+ | |||
+ // Length of overloaded intrinsic suffix. | |||
+ uint8_t OverloadedSuffixSize; | |||
+ | |||
+ // Required target features for this intrinsic. | |||
+ uint8_t RequiredExtensions; | |||
+ | |||
+ // Supported type, mask of BasicType. | |||
+ uint8_t TypeRangeMask; | |||
+ | |||
+ // Supported LMUL. | |||
+ uint8_t Log2LMULMask; | |||
+ | |||
+ // Number of fields, greater than 1 if it's segment load/store. | |||
+ uint8_t NF; | |||
+ }; | |||
+ | |||
+ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, | |||
+ const RVVIntrinsicRecord &RVVInstrRecord); | |||
+ | |||
+ LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); | |||
} // end namespace RISCV | |||
} // end namespace clang | |||
#endif // CLANG_SUPPORT_RISCVVINTRINSICUTILS_H |
clang/lib/Parse/ParsePragma.cpp
Show First 20 Lines • Show All 344 Lines • ▼ Show 20 Lines | |||
}; | |||
struct PragmaMaxTokensTotalHandler : public PragmaHandler { | |||
PragmaMaxTokensTotalHandler() : PragmaHandler("max_tokens_total") {} | |||
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | |||
Token &FirstToken) override; | |||
}; | |||
+ struct PragmaRISCVHandler : public PragmaHandler { | |||
+ PragmaRISCVHandler(Sema &Actions) | |||
+ : PragmaHandler("riscv"), Actions(Actions) {} | |||
+ void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | |||
+ Token &FirstToken) override; | |||
+ | |||
+ private: | |||
+ Sema &Actions; | |||
+ }; | |||
+ | |||
void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) { | |||
for (auto &T : Toks) | |||
T.setFlag(clang::Token::IsReinjected); | |||
} | |||
} // end namespace | |||
void Parser::initializePragmaHandlers() { | |||
AlignHandler = std::make_unique<PragmaAlignHandler>(); | |||
▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | |||
std::make_unique<PragmaAttributeHandler>(AttrFactory); | |||
PP.AddPragmaHandler("clang", AttributePragmaHandler.get()); | |||
MaxTokensHerePragmaHandler = std::make_unique<PragmaMaxTokensHereHandler>(); | |||
PP.AddPragmaHandler("clang", MaxTokensHerePragmaHandler.get()); | |||
MaxTokensTotalPragmaHandler = std::make_unique<PragmaMaxTokensTotalHandler>(); | |||
PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get()); | |||
+ | |||
+ if (getTargetInfo().getTriple().isRISCV()) { | |||
+ RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>(Actions); | |||
+ PP.AddPragmaHandler("clang", RISCVPragmaHandler.get()); | |||
+ } | |||
} | |||
void Parser::resetPragmaHandlers() { | |||
// Remove the pragma handlers we installed. | |||
PP.RemovePragmaHandler(AlignHandler.get()); | |||
AlignHandler.reset(); | |||
PP.RemovePragmaHandler("GCC", GCCVisibilityHandler.get()); | |||
GCCVisibilityHandler.reset(); | |||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | |||
PP.RemovePragmaHandler("clang", AttributePragmaHandler.get()); | |||
AttributePragmaHandler.reset(); | |||
PP.RemovePragmaHandler("clang", MaxTokensHerePragmaHandler.get()); | |||
MaxTokensHerePragmaHandler.reset(); | |||
PP.RemovePragmaHandler("clang", MaxTokensTotalPragmaHandler.get()); | |||
MaxTokensTotalPragmaHandler.reset(); | |||
+ | |||
+ if (getTargetInfo().getTriple().isRISCV()) { | |||
+ PP.RemovePragmaHandler("clang", RISCVPragmaHandler.get()); | |||
+ RISCVPragmaHandler.reset(); | |||
+ } | |||
} | |||
/// Handle the annotation token produced for #pragma unused(...) | |||
/// | |||
/// Each annot_pragma_unused is followed by the argument token so e.g. | |||
/// "#pragma unused(x,y)" becomes: | |||
/// annot_pragma_unused 'x' annot_pragma_unused 'y' | |||
void Parser::HandlePragmaUnused() { | |||
▲ Show 20 Lines • Show All 3,296 Lines • ▼ Show 20 Lines | |||
if (Tok.isNot(tok::eod)) { | |||
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | |||
<< "clang max_tokens_total"; | |||
return; | |||
} | |||
PP.overrideMaxTokens(MaxTokens, Loc); | |||
} | |||
+ | |||
+ // Handle '#pragma clang 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.Lex(Tok); | |||
+ if (Tok.isNot(tok::eod)) { | |||
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | |||
+ << "clang riscv intrinsic"; | |||
+ return; | |||
+ } | |||
+ | |||
+ Actions.DeclareRISCVVBuiltins = true; | |||
+ } |
clang/lib/Sema/CMakeLists.txt
Show First 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||
SemaInit.cpp | |||
SemaLambda.cpp | |||
SemaLookup.cpp | |||
SemaModule.cpp | |||
SemaObjCProperty.cpp | |||
SemaOpenMP.cpp | |||
SemaOverload.cpp | |||
SemaPseudoObject.cpp | |||
+ SemaRISCVVectorLookup.cpp | |||
SemaStmt.cpp | |||
SemaStmtAsm.cpp | |||
SemaStmtAttr.cpp | |||
SemaSYCL.cpp | |||
SemaTemplate.cpp | |||
SemaTemplateDeduction.cpp | |||
SemaTemplateInstantiate.cpp | |||
SemaTemplateInstantiateDecl.cpp | |||
SemaTemplateVariadic.cpp | |||
SemaType.cpp | |||
TypeLocBuilder.cpp | |||
DEPENDS | |||
ClangOpenCLBuiltinsImpl | |||
omp_gen | |||
LINK_LIBS | |||
clangAST | |||
clangAnalysis | |||
clangBasic | |||
clangEdit | |||
clangLex | |||
+ clangSupport | |||
) |
clang/lib/Sema/Sema.cpp
Show All 31 Lines | |||
#include "clang/Lex/HeaderSearchOptions.h" | |||
#include "clang/Lex/Preprocessor.h" | |||
#include "clang/Sema/CXXFieldCollector.h" | |||
#include "clang/Sema/DelayedDiagnostic.h" | |||
#include "clang/Sema/ExternalSemaSource.h" | |||
#include "clang/Sema/Initialization.h" | |||
#include "clang/Sema/MultiplexExternalSemaSource.h" | |||
#include "clang/Sema/ObjCMethodList.h" | |||
+ #include "clang/Sema/RISCVIntrinsicManager.h" | |||
#include "clang/Sema/Scope.h" | |||
#include "clang/Sema/ScopeInfo.h" | |||
#include "clang/Sema/SemaConsumer.h" | |||
#include "clang/Sema/SemaInternal.h" | |||
#include "clang/Sema/TemplateDeduction.h" | |||
#include "clang/Sema/TemplateInstCallback.h" | |||
#include "clang/Sema/TypoCorrection.h" | |||
#include "llvm/ADT/DenseMap.h" | |||
▲ Show 20 Lines • Show All 2,613 Lines • Show Last 20 Lines |
clang/lib/Sema/SemaLookup.cpp
Show All 23 Lines | |||
#include "clang/Basic/FileManager.h" | |||
#include "clang/Basic/LangOptions.h" | |||
#include "clang/Lex/HeaderSearch.h" | |||
#include "clang/Lex/ModuleLoader.h" | |||
#include "clang/Lex/Preprocessor.h" | |||
#include "clang/Sema/DeclSpec.h" | |||
#include "clang/Sema/Lookup.h" | |||
#include "clang/Sema/Overload.h" | |||
+ #include "clang/Sema/RISCVIntrinsicManager.h" | |||
#include "clang/Sema/Scope.h" | |||
#include "clang/Sema/ScopeInfo.h" | |||
#include "clang/Sema/Sema.h" | |||
#include "clang/Sema/SemaInternal.h" | |||
#include "clang/Sema/TemplateDeduction.h" | |||
#include "clang/Sema/TypoCorrection.h" | |||
#include "llvm/ADT/STLExtras.h" | |||
#include "llvm/ADT/SmallPtrSet.h" | |||
▲ Show 20 Lines • Show All 883 Lines • ▼ Show 20 Lines | |||
auto Index = isOpenCLBuiltin(II->getName()); | |||
if (Index.first) { | |||
InsertOCLBuiltinDeclarationsFromTable(*this, R, II, Index.first - 1, | |||
Index.second); | |||
return true; | |||
} | |||
} | |||
+ if (DeclareRISCVVBuiltins) { | |||
+ if (!RVIntrinsicManager) | |||
+ RVIntrinsicManager = CreateRISCVIntrinsicManager(*this); | |||
+ | |||
+ if (RVIntrinsicManager->CreateIntrinsicIfFound(R, II, PP)) | |||
+ return true; | |||
+ } | |||
+ | |||
// If this is a builtin on this (or all) targets, create the decl. | |||
if (unsigned BuiltinID = II->getBuiltinID()) { | |||
// In C++, C2x, and OpenCL (spec v1.2 s6.9.f), we don't have any | |||
// predefined library functions like 'malloc'. Instead, we'll just | |||
// error. | |||
if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL || | |||
getLangOpts().C2x) && | |||
Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) | |||
▲ Show 20 Lines • Show All 4,891 Lines • Show Last 20 Lines |
clang/lib/Sema/SemaRISCVVectorLookup.cpp
- This file was added.
+ //==- SemaRISCVVectorLookup.cpp - Name Lookup for RISC-V Vector Intrinsic -==// | |||
+ // | |||
+ // 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 | |||
+ // | |||
+ //===----------------------------------------------------------------------===// | |||
+ // | |||
+ // This file implements name lookup for RISC-V vector intrinsic. | |||
+ // | |||
+ //===----------------------------------------------------------------------===// | |||
+ | |||
+ #include "clang/AST/ASTContext.h" | |||
+ #include "clang/AST/Decl.h" | |||
+ #include "clang/Basic/Builtins.h" | |||
+ #include "clang/Basic/TargetInfo.h" | |||
+ #include "clang/Lex/Preprocessor.h" | |||
+ #include "clang/Sema/Lookup.h" | |||
+ #include "clang/Sema/RISCVIntrinsicManager.h" | |||
+ #include "clang/Sema/Sema.h" | |||
+ #include "clang/Support/RISCVVIntrinsicUtils.h" | |||
+ #include "llvm/ADT/SmallVector.h" | |||
+ #include <string> | |||
+ #include <vector> | |||
+ | |||
+ using namespace llvm; | |||
+ using namespace clang; | |||
+ using namespace clang::RISCV; | |||
+ | |||
+ namespace { | |||
+ | |||
+ // Function definition of a RVV intrinsic. | |||
+ struct RVVIntrinsicDef { | |||
+ /// Full function name with suffix, e.g. vadd_vv_i32m1. | |||
+ std::string Name; | |||
+ | |||
+ /// Overloaded function name, e.g. vadd. | |||
+ std::string OverloadName; | |||
+ | |||
+ /// Mapping to which clang built-in function, e.g. __builtin_rvv_vadd. | |||
+ std::string BuiltinName; | |||
+ | |||
+ /// Function signature, first element is return type. | |||
+ RVVTypes Signature; | |||
+ }; | |||
+ | |||
+ struct RVVOverloadIntrinsicDef { | |||
+ // Indexes of RISCVIntrinsicManagerImpl::IntrinsicList. | |||
+ SmallVector<size_t, 8> Indexes; | |||
+ }; | |||
+ | |||
+ } // namespace | |||
+ | |||
+ static const PrototypeDescriptor RVVSignatureTable[] = { | |||
+ #define DECL_SIGNATURE_TABLE | |||
+ #include "clang/Basic/riscv_vector_builtin_sema.inc" | |||
+ #undef DECL_SIGNATURE_TABLE | |||
+ }; | |||
+ | |||
+ static const RVVIntrinsicRecord RVVIntrinsicRecords[] = { | |||
+ #define DECL_INTRINSIC_RECORDS | |||
+ #include "clang/Basic/riscv_vector_builtin_sema.inc" | |||
+ #undef DECL_INTRINSIC_RECORDS | |||
+ }; | |||
+ | |||
+ // Get subsequence of signature table. | |||
+ static ArrayRef<PrototypeDescriptor> ProtoSeq2ArrayRef(uint16_t Index, | |||
+ uint8_t Length) { | |||
+ return makeArrayRef(&RVVSignatureTable[Index], Length); | |||
+ } | |||
+ | |||
+ static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) { | |||
+ QualType QT; | |||
+ switch (Type->getScalarType()) { | |||
+ case ScalarTypeKind::Void: | |||
+ QT = Context.VoidTy; | |||
+ break; | |||
+ case ScalarTypeKind::Size_t: | |||
+ QT = Context.getSizeType(); | |||
+ break; | |||
+ case ScalarTypeKind::Ptrdiff_t: | |||
+ QT = Context.getPointerDiffType(); | |||
+ break; | |||
+ case ScalarTypeKind::UnsignedLong: | |||
+ QT = Context.UnsignedLongTy; | |||
+ break; | |||
+ case ScalarTypeKind::SignedLong: | |||
+ QT = Context.LongTy; | |||
+ break; | |||
+ case ScalarTypeKind::Boolean: | |||
+ QT = Context.BoolTy; | |||
+ break; | |||
+ case ScalarTypeKind::SignedInteger: | |||
+ QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), true); | |||
+ break; | |||
+ case ScalarTypeKind::UnsignedInteger: | |||
+ QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), false); | |||
+ break; | |||
+ case ScalarTypeKind::Float: | |||
+ switch (Type->getElementBitwidth()) { | |||
+ case 64: | |||
+ QT = Context.DoubleTy; | |||
+ break; | |||
+ case 32: | |||
+ QT = Context.FloatTy; | |||
+ break; | |||
+ case 16: | |||
+ QT = Context.Float16Ty; | |||
+ break; | |||
+ default: | |||
+ llvm_unreachable("Unsupported floating point width."); | |||
+ } | |||
+ break; | |||
+ case Invalid: | |||
+ llvm_unreachable("Unhandled type."); | |||
+ } | |||
+ if (Type->isVector()) | |||
+ QT = Context.getScalableVectorType(QT, Type->getScale().getValue()); | |||
+ | |||
+ if (Type->isConstant()) | |||
+ QT = Context.getConstType(QT); | |||
+ | |||
+ // Transform the type to a pointer as the last step, if necessary. | |||
+ if (Type->isPointer()) | |||
+ QT = Context.getPointerType(QT); | |||
+ | |||
+ return QT; | |||
+ } | |||
+ | |||
+ namespace { | |||
+ class RISCVIntrinsicManagerImpl : public sema::RISCVIntrinsicManager { | |||
+ private: | |||
+ Sema &S; | |||
+ ASTContext &Context; | |||
+ | |||
+ // List of all RVV intrinsic. | |||
+ std::vector<RVVIntrinsicDef> IntrinsicList; | |||
+ // Mapping function name to index of IntrinsicList. | |||
+ StringMap<size_t> Intrinsics; | |||
+ // Mapping function name to RVVOverloadIntrinsicDef. | |||
+ StringMap<RVVOverloadIntrinsicDef> OverloadIntrinsics; | |||
+ | |||
+ // Create IntrinsicList | |||
+ void InitIntrinsicList(); | |||
+ | |||
+ // Create RVVIntrinsicDef. | |||
+ void InitRVVIntrinsic(const RVVIntrinsicRecord &Record, StringRef SuffixStr, | |||
+ StringRef OverloadedSuffixStr, bool IsMask, | |||
+ RVVTypes &Types); | |||
+ | |||
+ // Create FunctionDecl for a vector intrinsic. | |||
+ void CreateRVVIntrinsicDecl(LookupResult &LR, IdentifierInfo *II, | |||
+ Preprocessor &PP, unsigned Index, | |||
+ bool IsOverload); | |||
+ | |||
+ public: | |||
+ RISCVIntrinsicManagerImpl(clang::Sema &S) : S(S), Context(S.Context) { | |||
+ InitIntrinsicList(); | |||
+ } | |||
+ | |||
+ // Create RISC-V vector intrinsic and insert into symbol table if found, and | |||
+ // return true, otherwise return false. | |||
+ bool CreateIntrinsicIfFound(LookupResult &LR, IdentifierInfo *II, | |||
+ Preprocessor &PP) override; | |||
+ }; | |||
+ } // namespace | |||
+ | |||
+ void RISCVIntrinsicManagerImpl::InitIntrinsicList() { | |||
+ const TargetInfo &TI = Context.getTargetInfo(); | |||
+ bool HasVectorFloat32 = TI.hasFeature("zve32f"); | |||
+ bool HasVectorFloat64 = TI.hasFeature("zve64d"); | |||
+ bool HasZvfh = TI.hasFeature("experimental-zvfh"); | |||
+ bool HasRV64 = TI.hasFeature("64bit"); | |||
+ bool HasFullMultiply = TI.hasFeature("v"); | |||
+ | |||
+ // Construction of RVVIntrinsicRecords need to sync with createRVVIntrinsics | |||
+ // in RISCVVEmitter.cpp. | |||
+ for (auto &Record : RVVIntrinsicRecords) { | |||
+ // Create Intrinsics for each type and LMUL. | |||
+ BasicType BaseType = BasicType::Unknown; | |||
+ ArrayRef<PrototypeDescriptor> ProtoSeq = | |||
+ ProtoSeq2ArrayRef(Record.PrototypeIndex, Record.PrototypeLength); | |||
+ ArrayRef<PrototypeDescriptor> ProtoMaskSeq = ProtoSeq2ArrayRef( | |||
+ Record.MaskedPrototypeIndex, Record.MaskedPrototypeLength); | |||
+ ArrayRef<PrototypeDescriptor> SuffixProto = | |||
+ ProtoSeq2ArrayRef(Record.SuffixIndex, Record.SuffixLength); | |||
+ ArrayRef<PrototypeDescriptor> OverloadedSuffixProto = ProtoSeq2ArrayRef( | |||
+ Record.OverloadedSuffixIndex, Record.OverloadedSuffixSize); | |||
+ for (unsigned int TypeRangeMaskShift = 0; | |||
+ TypeRangeMaskShift <= static_cast<unsigned int>(BasicType::MaxOffset); | |||
+ ++TypeRangeMaskShift) { | |||
+ unsigned int BaseTypeI = 1 << TypeRangeMaskShift; | |||
+ BaseType = static_cast<BasicType>(BaseTypeI); | |||
+ | |||
+ if ((BaseTypeI & Record.TypeRangeMask) != BaseTypeI) | |||
+ continue; | |||
+ | |||
+ // Check requirement. | |||
+ if (BaseType == BasicType::Float16 && !HasZvfh) | |||
+ continue; | |||
+ | |||
+ if (BaseType == BasicType::Float32 && !HasVectorFloat32) | |||
+ continue; | |||
+ | |||
+ if (BaseType == BasicType::Float64 && !HasVectorFloat64) | |||
+ continue; | |||
+ | |||
+ if (((Record.RequiredExtensions & RVV_REQ_RV64) == RVV_REQ_RV64) && | |||
+ !HasRV64) | |||
+ continue; | |||
+ | |||
+ if ((BaseType == BasicType::Int64) && | |||
+ ((Record.RequiredExtensions & RVV_REQ_FullMultiply) == | |||
+ RVV_REQ_FullMultiply) && | |||
+ !HasFullMultiply) | |||
+ continue; | |||
+ | |||
+ // Expanded with different LMUL. | |||
+ for (int Log2LMUL = -3; Log2LMUL <= 3; Log2LMUL++) { | |||
+ if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3)))) | |||
+ continue; | |||
+ | |||
+ Optional<RVVTypes> Types = | |||
+ RVVType::computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq); | |||
+ | |||
+ // Ignored to create new intrinsic if there are any illegal types. | |||
+ if (!Types.hasValue()) | |||
+ continue; | |||
+ | |||
+ std::string SuffixStr = | |||
+ RVVIntrinsic::getSuffixStr(BaseType, Log2LMUL, SuffixProto); | |||
+ std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr( | |||
+ BaseType, Log2LMUL, OverloadedSuffixProto); | |||
+ | |||
+ // Create non-masked intrinsic. | |||
+ InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types); | |||
+ | |||
+ if (Record.MaskedPrototypeLength != 0) { | |||
+ // Create masked intrinsic. | |||
+ Optional<RVVTypes> MaskTypes = RVVType::computeTypes( | |||
+ BaseType, Log2LMUL, Record.NF, ProtoMaskSeq); | |||
+ | |||
+ InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true, | |||
+ *MaskTypes); | |||
+ } | |||
+ } | |||
+ } | |||
+ } | |||
+ } | |||
+ | |||
+ // Compute name and signatures for intrinsic with practical types. | |||
+ void RISCVIntrinsicManagerImpl::InitRVVIntrinsic( | |||
+ const RVVIntrinsicRecord &Record, StringRef SuffixStr, | |||
+ StringRef OverloadedSuffixStr, bool IsMask, RVVTypes &Signature) { | |||
+ // Function name, e.g. vadd_vv_i32m1. | |||
+ std::string Name = Record.Name; | |||
+ if (!SuffixStr.empty()) | |||
+ Name += "_" + SuffixStr.str(); | |||
+ | |||
+ if (IsMask) | |||
+ Name += "_m"; | |||
+ | |||
+ // Overloaded function name, e.g. vadd. | |||
+ std::string OverloadedName; | |||
+ if (!Record.OverloadedName) | |||
+ OverloadedName = StringRef(Record.Name).split("_").first.str(); | |||
+ else | |||
+ OverloadedName = Record.OverloadedName; | |||
+ if (!OverloadedSuffixStr.empty()) | |||
+ OverloadedName += "_" + OverloadedSuffixStr.str(); | |||
+ | |||
+ // clang built-in function name, e.g. __builtin_rvv_vadd. | |||
+ std::string BuiltinName = "__builtin_rvv_" + std::string(Record.Name); | |||
+ if (IsMask) | |||
+ BuiltinName += "_m"; | |||
+ | |||
+ // Put into IntrinsicList. | |||
+ size_t Index = IntrinsicList.size(); | |||
+ IntrinsicList.push_back({Name, OverloadedName, BuiltinName, Signature}); | |||
+ | |||
+ // Creating mapping to Intrinsics. | |||
+ Intrinsics.insert({Name, Index}); | |||
+ | |||
+ // Get the RVVOverloadIntrinsicDef. | |||
+ RVVOverloadIntrinsicDef &OverloadIntrinsicDef = | |||
+ OverloadIntrinsics[OverloadedName]; | |||
+ | |||
+ // And added the index. | |||
+ OverloadIntrinsicDef.Indexes.push_back(Index); | |||
+ } | |||
+ | |||
+ void RISCVIntrinsicManagerImpl::CreateRVVIntrinsicDecl(LookupResult &LR, | |||
+ IdentifierInfo *II, | |||
+ Preprocessor &PP, | |||
+ unsigned Index, | |||
+ bool IsOverload) { | |||
+ ASTContext &Context = S.Context; | |||
+ RVVIntrinsicDef &IDef = IntrinsicList[Index]; | |||
+ RVVTypes Sigs = IDef.Signature; | |||
+ size_t SigLength = Sigs.size(); | |||
+ RVVType *ReturnType = Sigs[0]; | |||
+ QualType RetType = RVVType2Qual(Context, ReturnType); | |||
+ SmallVector<QualType, 8> ArgTypes; | |||
+ QualType BuiltinFuncType; | |||
+ | |||
+ // Skip return type, and convert RVVType to QualType for arguments. | |||
+ for (size_t i = 1; i < SigLength; ++i) | |||
+ ArgTypes.push_back(RVVType2Qual(Context, Sigs[i])); | |||
+ | |||
+ FunctionProtoType::ExtProtoInfo PI( | |||
+ Context.getDefaultCallingConvention(false, false, true)); | |||
+ | |||
+ PI.Variadic = false; | |||
+ | |||
+ SourceLocation Loc = LR.getNameLoc(); | |||
+ BuiltinFuncType = Context.getFunctionType(RetType, ArgTypes, PI); | |||
+ DeclContext *Parent = Context.getTranslationUnitDecl(); | |||
+ | |||
+ FunctionDecl *RVVIntrinsicDecl = FunctionDecl::Create( | |||
+ Context, Parent, Loc, Loc, II, BuiltinFuncType, /*TInfo=*/nullptr, | |||
+ SC_Extern, S.getCurFPFeatures().isFPConstrained(), | |||
+ /*isInlineSpecified*/ false, | |||
+ /*hasWrittenPrototype*/ true); | |||
+ | |||
+ // Create Decl objects for each parameter, adding them to the | |||
+ // FunctionDecl. | |||
+ const auto *FP = cast<FunctionProtoType>(BuiltinFuncType); | |||
+ SmallVector<ParmVarDecl *, 8> ParmList; | |||
+ for (unsigned IParm = 0, E = FP->getNumParams(); IParm != E; ++IParm) { | |||
+ ParmVarDecl *Parm = | |||
+ ParmVarDecl::Create(Context, RVVIntrinsicDecl, Loc, Loc, nullptr, | |||
+ FP->getParamType(IParm), nullptr, SC_None, nullptr); | |||
+ Parm->setScopeInfo(0, IParm); | |||
+ ParmList.push_back(Parm); | |||
+ } | |||
+ RVVIntrinsicDecl->setParams(ParmList); | |||
+ | |||
+ // Add function attributes. | |||
+ if (IsOverload) | |||
+ RVVIntrinsicDecl->addAttr(OverloadableAttr::CreateImplicit(Context)); | |||
+ | |||
+ // Setup alias to __builtin_rvv_* | |||
+ IdentifierInfo &IntrinsicII = PP.getIdentifierTable().get(IDef.BuiltinName); | |||
+ RVVIntrinsicDecl->addAttr( | |||
+ BuiltinAliasAttr::CreateImplicit(S.Context, &IntrinsicII)); | |||
+ | |||
+ // Add to symbol table. | |||
+ LR.addDecl(RVVIntrinsicDecl); | |||
+ } | |||
+ | |||
+ bool RISCVIntrinsicManagerImpl::CreateIntrinsicIfFound(LookupResult &LR, | |||
+ IdentifierInfo *II, | |||
+ Preprocessor &PP) { | |||
+ StringRef Name = II->getName(); | |||
+ | |||
+ // Lookup the function name from the overload intrinsics first. | |||
+ auto OvIItr = OverloadIntrinsics.find(Name); | |||
+ if (OvIItr != OverloadIntrinsics.end()) { | |||
+ const RVVOverloadIntrinsicDef &OvIntrinsicDef = OvIItr->second; | |||
+ for (auto Index : OvIntrinsicDef.Indexes) | |||
+ CreateRVVIntrinsicDecl(LR, II, PP, Index, | |||
+ /*IsOverload*/ true); | |||
+ | |||
+ // If we added overloads, need to resolve the lookup result. | |||
+ LR.resolveKind(); | |||
+ return true; | |||
+ } | |||
+ | |||
+ // Lookup the function name from the intrinsics. | |||
+ auto Itr = Intrinsics.find(Name); | |||
+ if (Itr != Intrinsics.end()) { | |||
+ CreateRVVIntrinsicDecl(LR, II, PP, Itr->second, | |||
+ /*IsOverload*/ false); | |||
+ return true; | |||
+ } | |||
+ | |||
+ // It's not an RVV intrinsics. | |||
+ return false; | |||
+ } | |||
+ | |||
+ namespace clang { | |||
+ std::unique_ptr<clang::sema::RISCVIntrinsicManager> | |||
+ CreateRISCVIntrinsicManager(Sema &S) { | |||
+ return std::make_unique<RISCVIntrinsicManagerImpl>(S); | |||
+ } | |||
+ } // namespace clang |
clang/lib/Support/RISCVVIntrinsicUtils.cpp
Show First 20 Lines • Show All 867 Lines • ▼ Show 20 Lines | |||
Name += "_" + Suffix.str(); | |||
if (!OverloadedSuffix.empty()) | |||
OverloadedName += "_" + OverloadedSuffix.str(); | |||
if (IsMasked) { | |||
BuiltinName += "_m"; | |||
Name += "_m"; | |||
} | |||
- // Init RISC-V extensions | |||
- for (const auto &T : OutInTypes) { | |||
- if (T->isFloatVector(16) || T->isFloat(16)) | |||
- RISCVPredefinedMacros |= RISCVPredefinedMacro::Zvfh; | |||
- if (T->isFloatVector(32)) | |||
- RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELenFp32; | |||
- if (T->isFloatVector(64)) | |||
- RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELenFp64; | |||
- if (T->isVector(64)) | |||
- RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELen64; | |||
- } | |||
- for (auto Feature : RequiredFeatures) { | |||
- if (Feature == "RV64") | |||
- RISCVPredefinedMacros |= RISCVPredefinedMacro::RV64; | |||
- // Note: Full multiply instruction (mulh, mulhu, mulhsu, smul) for EEW=64 | |||
- // require V. | |||
- if (Feature == "FullMultiply" && | |||
- (RISCVPredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64)) | |||
- RISCVPredefinedMacros |= RISCVPredefinedMacro::V; | |||
- } | |||
- | |||
// Init OutputType and InputTypes | |||
OutputType = OutInTypes[0]; | |||
InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end()); | |||
// IntrinsicTypes is unmasked TA version index. Need to update it | |||
// if there is merge operand (It is always in first operand). | |||
IntrinsicTypes = NewIntrinsicTypes; | |||
if ((IsMasked && HasMaskedOffOperand) || | |||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||
if (!PD) | |||
llvm_unreachable("Error during parsing prototype."); | |||
PrototypeDescriptors.push_back(*PD); | |||
Prototypes = Prototypes.drop_front(Idx + 1); | |||
} | |||
return PrototypeDescriptors; | |||
} | |||
+ raw_ostream &operator<<(raw_ostream &OS, const RVVIntrinsicRecord &Record) { | |||
+ OS << "{"; | |||
+ OS << "\"" << Record.Name << "\","; | |||
+ if (Record.OverloadedName == nullptr || | |||
+ StringRef(Record.OverloadedName).empty()) | |||
+ OS << "nullptr,"; | |||
+ else | |||
+ OS << "\"" << Record.OverloadedName << "\","; | |||
+ OS << Record.PrototypeIndex << ","; | |||
+ OS << Record.MaskedPrototypeIndex << ","; | |||
+ OS << Record.SuffixIndex << ","; | |||
+ OS << Record.OverloadedSuffixIndex << ","; | |||
+ OS << (int)Record.PrototypeLength << ","; | |||
+ OS << (int)Record.MaskedPrototypeLength << ","; | |||
+ OS << (int)Record.SuffixLength << ","; | |||
+ OS << (int)Record.OverloadedSuffixSize << ","; | |||
+ OS << (int)Record.RequiredExtensions << ","; | |||
+ OS << (int)Record.TypeRangeMask << ","; | |||
+ OS << (int)Record.Log2LMULMask << ","; | |||
+ OS << (int)Record.NF << ","; | |||
+ OS << "},\n"; | |||
+ return OS; | |||
+ } | |||
+ | |||
} // end namespace RISCV | |||
} // end namespace clang |
clang/test/Sema/riscv-bad-intrinsic-pragma.c
- This file was added.
+ // RUN: %clang_cc1 -triple riscv64 -target-feature +v %s -emit-llvm -o - \ | |||
+ // RUN: 2>&1 | FileCheck %s | |||
+ | |||
+ #pragma clang riscv intrinsic vvvv | |||
+ // CHECK: warning: unexpected argument 'vvvv' to '#pragma riscv'; expected 'vector' [-Wignored-pragmas] | |||
+ | |||
+ #pragma clang riscv what + 3241 | |||
+ // CHECK: warning: unexpected argument 'what' to '#pragma riscv'; expected 'intrinsic' [-Wignored-pragmas] | |||
+ #pragma clang riscv int i = 12; | |||
+ // CHECK: warning: unexpected argument 'int' to '#pragma riscv'; expected 'intrinsic' [-Wignored-pragmas] | |||
+ #pragma clang riscv intrinsic vector bar | |||
+ // CHECK: warning: extra tokens at end of '#pragma clang riscv intrinsic' - ignored [-Wignored-pragmas] | |||
+ | |||
+ #define FOO 0 | |||
+ | |||
+ int main() | |||
+ { | |||
+ return FOO; | |||
+ } | |||
+ | |||
+ // Make sure no more warnings | |||
+ // CHECK-NOT: warning: |
clang/test/Sema/riscv-intrinsic-pragma.c
- This file was added.
+ // RUN: %clang_cc1 -triple riscv64 -target-feature +v -emit-llvm -o - -verify %s | |||
+ | |||
+ #pragma clang riscv intrinsic vector | |||
+ // expected-no-diagnostics |
clang/utils/TableGen/RISCVVEmitter.cpp
Show All 14 Lines | |||
//===----------------------------------------------------------------------===// | |||
#include "clang/Support/RISCVVIntrinsicUtils.h" | |||
#include "llvm/ADT/ArrayRef.h" | |||
#include "llvm/ADT/SmallSet.h" | |||
#include "llvm/ADT/StringExtras.h" | |||
#include "llvm/ADT/StringMap.h" | |||
#include "llvm/ADT/StringSet.h" | |||
+ #include "llvm/ADT/StringSwitch.h" | |||
#include "llvm/ADT/Twine.h" | |||
#include "llvm/TableGen/Error.h" | |||
#include "llvm/TableGen/Record.h" | |||
#include <numeric> | |||
using namespace llvm; | |||
using namespace clang::RISCV; | |||
namespace { | |||
+ struct SemaRecord { | |||
+ // Intrinsic name, e.g. vadd_vv | |||
+ std::string Name; | |||
+ | |||
+ // Overloaded intrinsic name, could be empty if can be computed from Name | |||
+ // e.g. vadd | |||
+ std::string OverloadedName; | |||
+ | |||
+ // Supported type, mask of BasicType. | |||
+ unsigned TypeRangeMask; | |||
+ | |||
+ // Supported LMUL. | |||
+ unsigned Log2LMULMask; | |||
+ | |||
+ // Required extensions for this intrinsic. | |||
+ unsigned RequiredExtensions; | |||
+ | |||
+ // Prototype for this intrinsic. | |||
+ SmallVector<PrototypeDescriptor> Prototype; | |||
+ | |||
+ // Prototype for masked intrinsic. | |||
+ SmallVector<PrototypeDescriptor> MaskedPrototype; | |||
+ | |||
+ // Suffix of intrinsic name. | |||
+ SmallVector<PrototypeDescriptor> Suffix; | |||
+ | |||
+ // Suffix of overloaded intrinsic name. | |||
+ SmallVector<PrototypeDescriptor> OverloadedSuffix; | |||
+ | |||
+ // Number of field, large than 1 if it's segment load/store. | |||
+ unsigned NF; | |||
+ }; | |||
+ | |||
+ // Compressed function signature table. | |||
+ class SemaSignatureTable { | |||
+ private: | |||
+ std::vector<PrototypeDescriptor> SignatureTable; | |||
+ | |||
+ void insert(ArrayRef<PrototypeDescriptor> Signature); | |||
+ | |||
+ public: | |||
+ static constexpr unsigned INVALID_INDEX = ~0U; | |||
+ | |||
+ // Create compressed signature table from SemaRecords. | |||
+ void init(ArrayRef<SemaRecord> SemaRecords); | |||
+ | |||
+ // Query the Signature, return INVALID_INDEX if not found. | |||
+ unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature); | |||
+ | |||
+ /// Print signature table in RVVHeader Record to \p OS | |||
+ void print(raw_ostream &OS); | |||
+ }; | |||
+ | |||
class RVVEmitter { | |||
private: | |||
RecordKeeper &Records; | |||
public: | |||
RVVEmitter(RecordKeeper &R) : Records(R) {} | |||
/// Emit riscv_vector.h | |||
void createHeader(raw_ostream &o); | |||
/// Emit all the __builtin prototypes and code needed by Sema. | |||
void createBuiltins(raw_ostream &o); | |||
/// Emit all the information needed to map builtin -> LLVM IR intrinsic. | |||
void createCodeGen(raw_ostream &o); | |||
+ /// Emit all the information needed by SemaRISCVVectorLookup.cpp. | |||
+ /// We've large number of intrinsic function for RVV, creating a customized | |||
+ /// could speed up the compilation time. | |||
+ void createSema(raw_ostream &o); | |||
+ | |||
private: | |||
- /// Create all intrinsics and add them to \p Out | |||
- void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out); | |||
+ /// Create all intrinsics and add them to \p Out and SemaRecords. | |||
+ void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out, | |||
+ std::vector<SemaRecord> *SemaRecords = nullptr); | |||
+ /// Create all intrinsic records and SemaSignatureTable from SemaRecords. | |||
+ void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, | |||
+ SemaSignatureTable &SST, | |||
+ ArrayRef<SemaRecord> SemaRecords); | |||
+ | |||
/// Print HeaderCode in RVVHeader Record to \p Out | |||
void printHeaderCode(raw_ostream &OS); | |||
- | |||
- /// 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 emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros, | |||
- raw_ostream &o); | |||
}; | |||
} // namespace | |||
static BasicType ParseBasicType(char c) { | |||
switch (c) { | |||
case 'c': | |||
return BasicType::Int8; | |||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | |||
// VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is | |||
// always last operand. | |||
if (RVVI->hasVL()) | |||
OS << ", Ops.back()->getType()"; | |||
OS << "};\n"; | |||
OS << " break;\n"; | |||
} | |||
- void emitIntrinsicFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) { | |||
- OS << "__attribute__((__clang_builtin_alias__("; | |||
- OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n"; | |||
- OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getName() << "("; | |||
- // Emit function arguments | |||
- const RVVTypes &InputTypes = RVVI.getInputTypes(); | |||
- if (!InputTypes.empty()) { | |||
- ListSeparator LS; | |||
- for (unsigned i = 0; i < InputTypes.size(); ++i) | |||
- OS << LS << InputTypes[i]->getTypeStr(); | |||
- } | |||
- OS << ");\n"; | |||
- } | |||
+ //===----------------------------------------------------------------------===// | |||
+ // SemaSignatureTable implementation | |||
+ //===----------------------------------------------------------------------===// | |||
+ void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) { | |||
+ // Sort signature entries by length, let longer signature insert first, to | |||
+ // make it more possible to reuse table entries, that can reduce ~10% table | |||
+ // size. | |||
+ struct Compare { | |||
+ bool operator()(const SmallVector<PrototypeDescriptor> &A, | |||
+ const SmallVector<PrototypeDescriptor> &B) const { | |||
+ if (A.size() != B.size()) | |||
+ return A.size() > B.size(); | |||
+ | |||
+ size_t Len = A.size(); | |||
+ for (size_t i = 0; i < Len; ++i) { | |||
+ if (A[i] != B[i]) | |||
+ return A[i] < B[i]; | |||
+ } | |||
+ | |||
+ return false; | |||
+ } | |||
+ }; | |||
- void emitOverloadedFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) { | |||
- OS << "__attribute__((__clang_builtin_alias__("; | |||
- OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n"; | |||
- OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getOverloadedName() | |||
- << "("; | |||
- // Emit function arguments | |||
- const RVVTypes &InputTypes = RVVI.getInputTypes(); | |||
- if (!InputTypes.empty()) { | |||
- ListSeparator LS; | |||
- for (unsigned i = 0; i < InputTypes.size(); ++i) | |||
- OS << LS << InputTypes[i]->getTypeStr(); | |||
+ std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures; | |||
+ auto InsertToSignatureSet = | |||
+ [&](const SmallVector<PrototypeDescriptor> &Signature) { | |||
+ if (Signature.empty()) | |||
+ return; | |||
+ | |||
+ Signatures.insert(Signature); | |||
+ }; | |||
+ | |||
+ assert(!SemaRecords.empty()); | |||
+ | |||
+ llvm::for_each(SemaRecords, [&](const SemaRecord &SR) { | |||
+ InsertToSignatureSet(SR.Prototype); | |||
+ InsertToSignatureSet(SR.MaskedPrototype); | |||
+ InsertToSignatureSet(SR.Suffix); | |||
+ InsertToSignatureSet(SR.OverloadedSuffix); | |||
+ }); | |||
+ | |||
+ llvm::for_each(Signatures, [this](auto &Sig) { insert(Sig); }); | |||
+ } | |||
+ | |||
+ void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) { | |||
+ if (getIndex(Signature) != INVALID_INDEX) | |||
+ return; | |||
+ | |||
+ // Insert Signature into SignatureTable if not found in the table. | |||
+ SignatureTable.insert(SignatureTable.begin(), Signature.begin(), | |||
+ Signature.end()); | |||
+ } | |||
+ | |||
+ unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) { | |||
+ // Empty signature could be point into any index since there is length | |||
+ // field when we use, so just always point it to 0. | |||
+ if (Signature.empty()) | |||
+ return 0; | |||
+ | |||
+ // Checking Signature already in table or not. | |||
+ if (Signature.size() < SignatureTable.size()) { | |||
+ size_t Bound = SignatureTable.size() - Signature.size() + 1; | |||
+ for (size_t Index = 0; Index < Bound; ++Index) { | |||
+ if (equal(Signature.begin(), Signature.end(), | |||
+ SignatureTable.begin() + Index)) | |||
+ return Index; | |||
+ } | |||
} | |||
- OS << ");\n"; | |||
+ | |||
+ return INVALID_INDEX; | |||
+ } | |||
+ | |||
+ void SemaSignatureTable::print(raw_ostream &OS) { | |||
+ for (const auto &Sig : SignatureTable) | |||
+ OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", " | |||
+ << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM) | |||
+ << "),\n"; | |||
} | |||
//===----------------------------------------------------------------------===// | |||
// RVVEmitter implementation | |||
//===----------------------------------------------------------------------===// | |||
void RVVEmitter::createHeader(raw_ostream &OS) { | |||
OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " | |||
Show All 18 Lines | |||
OS << "#ifndef __riscv_vector\n"; | |||
OS << "#error \"Vector intrinsics require the vector extension.\"\n"; | |||
OS << "#endif\n\n"; | |||
OS << "#ifdef __cplusplus\n"; | |||
OS << "extern \"C\" {\n"; | |||
OS << "#endif\n\n"; | |||
- printHeaderCode(OS); | |||
+ OS << "#pragma clang riscv intrinsic vector\n\n"; | |||
- std::vector<std::unique_ptr<RVVIntrinsic>> Defs; | |||
- createRVVIntrinsics(Defs); | |||
+ printHeaderCode(OS); | |||
auto printType = [&](auto T) { | |||
OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() | |||
<< ";\n"; | |||
}; | |||
constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; | |||
// Print RVV boolean types. | |||
Show All 23 Lines | |||
for (int Log2LMUL : Log2LMULs) { | |||
auto T = RVVType::computeType(BasicType::Float16, Log2LMUL, | |||
PrototypeDescriptor::Vector); | |||
if (T) | |||
printType(T.value()); | |||
} | |||
OS << "#endif\n"; | |||
- OS << "#if defined(__riscv_f)\n"; | |||
+ OS << "#if (__riscv_v_elen_fp >= 32)\n"; | |||
for (int Log2LMUL : Log2LMULs) { | |||
auto T = RVVType::computeType(BasicType::Float32, Log2LMUL, | |||
PrototypeDescriptor::Vector); | |||
if (T) | |||
printType(T.value()); | |||
} | |||
OS << "#endif\n"; | |||
- OS << "#if defined(__riscv_d)\n"; | |||
+ OS << "#if (__riscv_v_elen_fp >= 64)\n"; | |||
for (int Log2LMUL : Log2LMULs) { | |||
auto T = RVVType::computeType(BasicType::Float64, Log2LMUL, | |||
PrototypeDescriptor::Vector); | |||
if (T) | |||
printType(T.value()); | |||
} | |||
OS << "#endif\n\n"; | |||
- // The same extension include in the same arch guard marco. | |||
- llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, | |||
- const std::unique_ptr<RVVIntrinsic> &B) { | |||
- return A->getRISCVPredefinedMacros() < B->getRISCVPredefinedMacros(); | |||
- }); | |||
- | |||
- OS << "#define __rvv_ai static __inline__\n"; | |||
- | |||
- // Print intrinsic functions with macro | |||
- emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { | |||
- OS << "__rvv_ai "; | |||
- emitIntrinsicFuncDef(Inst, OS); | |||
- }); | |||
- | |||
- OS << "#undef __rvv_ai\n\n"; | |||
- | |||
OS << "#define __riscv_v_intrinsic_overloading 1\n"; | |||
- // Print Overloaded APIs | |||
- OS << "#define __rvv_aio static __inline__ " | |||
- "__attribute__((__overloadable__))\n"; | |||
- | |||
- emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { | |||
- if (!Inst.isMasked() && !Inst.hasUnMaskedOverloaded()) | |||
- return; | |||
- OS << "__rvv_aio "; | |||
- emitOverloadedFuncDef(Inst, OS); | |||
- }); | |||
- | |||
- OS << "#undef __rvv_aio\n"; | |||
- | |||
OS << "\n#ifdef __cplusplus\n"; | |||
OS << "}\n"; | |||
OS << "#endif // __cplusplus\n"; | |||
OS << "#endif // __RISCV_VECTOR_H\n"; | |||
} | |||
void RVVEmitter::createBuiltins(raw_ostream &OS) { | |||
std::vector<std::unique_ptr<RVVIntrinsic>> Defs; | |||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | |||
else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) | |||
PrintFatalError("Builtin with same name has different IntrinsicTypes"); | |||
} | |||
emitCodeGenSwitchBody(Defs.back().get(), OS); | |||
OS << "\n"; | |||
} | |||
void RVVEmitter::createRVVIntrinsics( | |||
- std::vector<std::unique_ptr<RVVIntrinsic>> &Out) { | |||
+ std::vector<std::unique_ptr<RVVIntrinsic>> &Out, | |||
+ std::vector<SemaRecord> *SemaRecords) { | |||
std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); | |||
for (auto *R : RV) { | |||
StringRef Name = R->getValueAsString("Name"); | |||
StringRef SuffixProto = R->getValueAsString("Suffix"); | |||
StringRef OverloadedName = R->getValueAsString("OverloadedName"); | |||
StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix"); | |||
StringRef Prototypes = R->getValueAsString("Prototype"); | |||
StringRef TypeRange = R->getValueAsString("TypeRange"); | |||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | |||
Name, SuffixStr, OverloadedName, OverloadedSuffixStr, | |||
MaskedIRName, | |||
/*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicy, | |||
HasUnMaskedOverloaded, HasBuiltinAlias, MaskedManualCodegen, | |||
*MaskTypes, IntrinsicTypes, RequiredFeatures, NF)); | |||
} | |||
} // end for Log2LMULList | |||
} // end for TypeRange | |||
+ | |||
+ // We don't emit vsetvli and vsetvlimax for SemaRecord. | |||
+ // They are written in riscv_vector.td and will emit those marco define in | |||
+ // riscv_vector.h | |||
+ if (Name == "vsetvli" || Name == "vsetvlimax") | |||
+ continue; | |||
+ | |||
+ if (!SemaRecords) | |||
+ continue; | |||
+ | |||
+ // Create SemaRecord | |||
+ SemaRecord SR; | |||
+ SR.Name = Name.str(); | |||
+ SR.OverloadedName = OverloadedName.str(); | |||
+ BasicType TypeRangeMask = BasicType::Unknown; | |||
+ for (char I : TypeRange) | |||
+ TypeRangeMask |= ParseBasicType(I); | |||
+ | |||
+ SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask); | |||
+ | |||
+ unsigned Log2LMULMask = 0; | |||
+ for (int Log2LMUL : Log2LMULList) | |||
+ Log2LMULMask |= 1 << (Log2LMUL + 3); | |||
+ | |||
+ SR.Log2LMULMask = Log2LMULMask; | |||
+ | |||
+ SR.RequiredExtensions = 0; | |||
+ for (auto RequiredFeature : RequiredFeatures) { | |||
+ RVVRequire RequireExt = StringSwitch<RVVRequire>(RequiredFeature) | |||
+ .Case("RV64", RVV_REQ_RV64) | |||
+ .Case("FullMultiply", RVV_REQ_FullMultiply) | |||
+ .Default(RVV_REQ_None); | |||
+ assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?"); | |||
+ SR.RequiredExtensions |= RequireExt; | |||
+ } | |||
+ | |||
+ SR.NF = NF; | |||
+ | |||
+ SR.Prototype = std::move(Prototype); | |||
+ | |||
+ if (HasMasked) | |||
+ SR.MaskedPrototype = std::move(MaskedPrototype); | |||
+ | |||
+ SR.Suffix = parsePrototypes(SuffixProto); | |||
+ SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto); | |||
+ | |||
+ SemaRecords->push_back(SR); | |||
} | |||
} | |||
void RVVEmitter::printHeaderCode(raw_ostream &OS) { | |||
std::vector<Record *> RVVHeaders = | |||
Records.getAllDerivedDefinitions("RVVHeader"); | |||
for (auto *R : RVVHeaders) { | |||
StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); | |||
OS << HeaderCodeStr.str(); | |||
} | |||
} | |||
- void RVVEmitter::emitArchMacroAndBody( | |||
- std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS, | |||
- std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) { | |||
- RISCVPredefinedMacroT PrevMacros = | |||
- (*Defs.begin())->getRISCVPredefinedMacros(); | |||
- bool NeedEndif = emitMacroRestrictionStr(PrevMacros, OS); | |||
- for (auto &Def : Defs) { | |||
- RISCVPredefinedMacroT CurMacros = Def->getRISCVPredefinedMacros(); | |||
- if (CurMacros != PrevMacros) { | |||
- if (NeedEndif) | |||
- OS << "#endif\n\n"; | |||
- NeedEndif = emitMacroRestrictionStr(CurMacros, OS); | |||
- PrevMacros = CurMacros; | |||
- } | |||
- if (Def->hasBuiltinAlias()) | |||
- PrintBody(OS, *Def); | |||
+ void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, | |||
+ SemaSignatureTable &SST, | |||
+ ArrayRef<SemaRecord> SemaRecords) { | |||
+ SST.init(SemaRecords); | |||
+ | |||
+ for (const auto &SR : SemaRecords) { | |||
+ Out.emplace_back(RVVIntrinsicRecord()); | |||
+ RVVIntrinsicRecord &R = Out.back(); | |||
+ R.Name = SR.Name.c_str(); | |||
+ R.OverloadedName = SR.OverloadedName.c_str(); | |||
+ R.PrototypeIndex = SST.getIndex(SR.Prototype); | |||
+ R.MaskedPrototypeIndex = SST.getIndex(SR.MaskedPrototype); | |||
+ R.SuffixIndex = SST.getIndex(SR.Suffix); | |||
+ R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix); | |||
+ R.PrototypeLength = SR.Prototype.size(); | |||
+ R.MaskedPrototypeLength = SR.MaskedPrototype.size(); | |||
+ R.SuffixLength = SR.Suffix.size(); | |||
+ R.OverloadedSuffixSize = SR.OverloadedSuffix.size(); | |||
+ R.RequiredExtensions = SR.RequiredExtensions; | |||
+ R.TypeRangeMask = SR.TypeRangeMask; | |||
+ R.Log2LMULMask = SR.Log2LMULMask; | |||
+ R.NF = SR.NF; | |||
+ | |||
+ assert(R.PrototypeIndex != | |||
+ static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); | |||
+ assert(R.MaskedPrototypeIndex != | |||
+ static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); | |||
+ assert(R.SuffixIndex != | |||
+ static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); | |||
+ assert(R.OverloadedSuffixIndex != | |||
+ static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); | |||
} | |||
- if (NeedEndif) | |||
- OS << "#endif\n\n"; | |||
} | |||
- bool RVVEmitter::emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros, | |||
- raw_ostream &OS) { | |||
- if (PredefinedMacros == RISCVPredefinedMacro::Basic) | |||
- return false; | |||
- OS << "#if "; | |||
- ListSeparator LS(" && "); | |||
- if (PredefinedMacros & RISCVPredefinedMacro::V) | |||
- OS << LS << "defined(__riscv_v)"; | |||
- if (PredefinedMacros & RISCVPredefinedMacro::Zvfh) | |||
- OS << LS << "defined(__riscv_zvfh)"; | |||
- if (PredefinedMacros & RISCVPredefinedMacro::RV64) | |||
- OS << LS << "(__riscv_xlen == 64)"; | |||
- if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64) | |||
- OS << LS << "(__riscv_v_elen >= 64)"; | |||
- if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp32) | |||
- OS << LS << "(__riscv_v_elen_fp >= 32)"; | |||
- if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp64) | |||
- OS << LS << "(__riscv_v_elen_fp >= 64)"; | |||
- OS << "\n"; | |||
- return true; | |||
+ void RVVEmitter::createSema(raw_ostream &OS) { | |||
+ std::vector<std::unique_ptr<RVVIntrinsic>> Defs; | |||
+ std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords; | |||
+ SemaSignatureTable SST; | |||
+ std::vector<SemaRecord> SemaRecords; | |||
+ | |||
+ createRVVIntrinsics(Defs, &SemaRecords); | |||
+ | |||
+ createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords); | |||
+ | |||
+ // Emit signature table for SemaRISCVVectorLookup.cpp. | |||
+ OS << "#ifdef DECL_SIGNATURE_TABLE\n"; | |||
+ SST.print(OS); | |||
+ OS << "#endif\n"; | |||
+ | |||
+ // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp. | |||
+ OS << "#ifdef DECL_INTRINSIC_RECORDS\n"; | |||
+ for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords) | |||
+ OS << Record; | |||
+ OS << "#endif\n"; | |||
} | |||
namespace clang { | |||
void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { | |||
RVVEmitter(Records).createHeader(OS); | |||
} | |||
void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { | |||
RVVEmitter(Records).createBuiltins(OS); | |||
} | |||
void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { | |||
RVVEmitter(Records).createCodeGen(OS); | |||
} | |||
+ void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { | |||
+ RVVEmitter(Records).createSema(OS); | |||
+ } | |||
+ | |||
} // End namespace clang |
clang/utils/TableGen/TableGen.cpp
Show First 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | |||
GenArmCdeHeader, | |||
GenArmCdeBuiltinDef, | |||
GenArmCdeBuiltinSema, | |||
GenArmCdeBuiltinCG, | |||
GenArmCdeBuiltinAliases, | |||
GenRISCVVectorHeader, | |||
GenRISCVVectorBuiltins, | |||
GenRISCVVectorBuiltinCG, | |||
+ GenRISCVVectorBuiltinSema, | |||
GenAttrDocs, | |||
GenDiagDocs, | |||
GenOptDocs, | |||
GenDataCollectors, | |||
GenTestPragmaAttributeSupportedAttributes | |||
}; | |||
namespace { | |||
▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | |||
clEnumValN(GenArmCdeBuiltinAliases, "gen-arm-cde-builtin-aliases", | |||
"Generate list of valid ARM CDE builtin aliases for clang"), | |||
clEnumValN(GenRISCVVectorHeader, "gen-riscv-vector-header", | |||
"Generate riscv_vector.h for clang"), | |||
clEnumValN(GenRISCVVectorBuiltins, "gen-riscv-vector-builtins", | |||
"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", | |||
"Generate diagnostic documentation"), | |||
clEnumValN(GenOptDocs, "gen-opt-docs", "Generate option documentation"), | |||
clEnumValN(GenDataCollectors, "gen-clang-data-collectors", | |||
"Generate data collectors for AST nodes"), | |||
clEnumValN(GenTestPragmaAttributeSupportedAttributes, | |||
▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | |||
EmitRVVHeader(Records, OS); | |||
break; | |||
case GenRISCVVectorBuiltins: | |||
EmitRVVBuiltins(Records, OS); | |||
break; | |||
case GenRISCVVectorBuiltinCG: | |||
EmitRVVBuiltinCG(Records, OS); | |||
break; | |||
+ case GenRISCVVectorBuiltinSema: | |||
+ EmitRVVBuiltinSema(Records, OS); | |||
+ break; | |||
case GenAttrDocs: | |||
EmitClangAttrDocs(Records, OS); | |||
break; | |||
case GenDiagDocs: | |||
EmitClangDiagDocs(Records, OS); | |||
break; | |||
case GenOptDocs: | |||
EmitClangOptDocs(Records, OS); | |||
Show All 31 Lines |
clang/utils/TableGen/TableGenBackends.h
Show First 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | |||
void EmitMveBuiltinDef(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); | |||
void EmitMveBuiltinSema(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); | |||
void EmitMveBuiltinCG(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); | |||
void EmitMveBuiltinAliases(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); | |||
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); | |||
void EmitCdeBuiltinSema(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); | |||
void EmitCdeBuiltinCG(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); | |||
void EmitCdeBuiltinAliases(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); | |||
void EmitClangAttrDocs(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); | |||
Show All 17 Lines |
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK