mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-05-17 19:36:48 +00:00
[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 <kito.cheng@sifive.com> Co-Authored-by: Hsiangkai Wang <kai.wang@sifive.com> Reviewed By: khchen, aaron.ballman Differential Revision: https://reviews.llvm.org/D111617
This commit is contained in:
parent
2f9fa9ef53
commit
7a5cb15ea6
@ -90,3 +90,6 @@ clang_tablegen(riscv_vector_builtins.inc -gen-riscv-vector-builtins
|
|||||||
clang_tablegen(riscv_vector_builtin_cg.inc -gen-riscv-vector-builtin-codegen
|
clang_tablegen(riscv_vector_builtin_cg.inc -gen-riscv-vector-builtin-codegen
|
||||||
SOURCE riscv_vector.td
|
SOURCE riscv_vector.td
|
||||||
TARGET ClangRISCVVectorBuiltinCG)
|
TARGET ClangRISCVVectorBuiltinCG)
|
||||||
|
clang_tablegen(riscv_vector_builtin_sema.inc -gen-riscv-vector-builtin-sema
|
||||||
|
SOURCE riscv_vector.td
|
||||||
|
TARGET ClangRISCVVectorBuiltinSema)
|
||||||
|
@ -908,6 +908,9 @@ PRAGMA_ANNOTATION(pragma_fp)
|
|||||||
// Annotation for the attribute pragma directives - #pragma clang attribute ...
|
// Annotation for the attribute pragma directives - #pragma clang attribute ...
|
||||||
PRAGMA_ANNOTATION(pragma_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.
|
// Annotations for module import translated from #include etc.
|
||||||
ANNOTATION(module_include)
|
ANNOTATION(module_include)
|
||||||
ANNOTATION(module_begin)
|
ANNOTATION(module_begin)
|
||||||
|
@ -215,6 +215,7 @@ class Parser : public CodeCompletionHandler {
|
|||||||
std::unique_ptr<PragmaHandler> AttributePragmaHandler;
|
std::unique_ptr<PragmaHandler> AttributePragmaHandler;
|
||||||
std::unique_ptr<PragmaHandler> MaxTokensHerePragmaHandler;
|
std::unique_ptr<PragmaHandler> MaxTokensHerePragmaHandler;
|
||||||
std::unique_ptr<PragmaHandler> MaxTokensTotalPragmaHandler;
|
std::unique_ptr<PragmaHandler> MaxTokensTotalPragmaHandler;
|
||||||
|
std::unique_ptr<PragmaHandler> RISCVPragmaHandler;
|
||||||
|
|
||||||
std::unique_ptr<CommentHandler> CommentSemaHandler;
|
std::unique_ptr<CommentHandler> CommentSemaHandler;
|
||||||
|
|
||||||
|
36
clang/include/clang/Sema/RISCVIntrinsicManager.h
Normal file
36
clang/include/clang/Sema/RISCVIntrinsicManager.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//===- 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
|
@ -226,6 +226,7 @@ namespace sema {
|
|||||||
class FunctionScopeInfo;
|
class FunctionScopeInfo;
|
||||||
class LambdaScopeInfo;
|
class LambdaScopeInfo;
|
||||||
class PossiblyUnreachableDiag;
|
class PossiblyUnreachableDiag;
|
||||||
|
class RISCVIntrinsicManager;
|
||||||
class SemaPPCallbacks;
|
class SemaPPCallbacks;
|
||||||
class TemplateDeductionInfo;
|
class TemplateDeductionInfo;
|
||||||
}
|
}
|
||||||
@ -1587,7 +1588,12 @@ public:
|
|||||||
/// assignment.
|
/// assignment.
|
||||||
llvm::DenseMap<const VarDecl *, int> RefsMinusAssignments;
|
llvm::DenseMap<const VarDecl *, int> RefsMinusAssignments;
|
||||||
|
|
||||||
|
/// Indicate RISC-V vector builtin functions enabled or not.
|
||||||
|
bool DeclareRISCVVBuiltins = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::unique_ptr<sema::RISCVIntrinsicManager> RVIntrinsicManager;
|
||||||
|
|
||||||
Optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo;
|
Optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo;
|
||||||
|
|
||||||
bool WarnedDarwinSDKInfoMissing = false;
|
bool WarnedDarwinSDKInfoMissing = false;
|
||||||
@ -13590,6 +13596,8 @@ void Sema::PragmaStack<Sema::AlignPackInfo>::Act(SourceLocation PragmaLocation,
|
|||||||
llvm::StringRef StackSlotLabel,
|
llvm::StringRef StackSlotLabel,
|
||||||
AlignPackInfo Value);
|
AlignPackInfo Value);
|
||||||
|
|
||||||
|
std::unique_ptr<sema::RISCVIntrinsicManager>
|
||||||
|
CreateRISCVIntrinsicManager(Sema &S);
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
class raw_ostream;
|
||||||
|
} // end namespace llvm
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
namespace RISCV {
|
namespace RISCV {
|
||||||
|
|
||||||
@ -104,12 +108,14 @@ struct PrototypeDescriptor {
|
|||||||
uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier);
|
uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier);
|
||||||
|
|
||||||
bool operator!=(const PrototypeDescriptor &PD) const {
|
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 {
|
bool operator==(const PrototypeDescriptor &PD) const {
|
||||||
return !(PD.PT <= PT && PD.VTM <= VTM && PD.TM <= TM);
|
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 Mask;
|
||||||
static const PrototypeDescriptor Vector;
|
static const PrototypeDescriptor Vector;
|
||||||
static const PrototypeDescriptor VL;
|
static const PrototypeDescriptor VL;
|
||||||
@ -224,8 +230,12 @@ public:
|
|||||||
bool isFloat(unsigned Width) const {
|
bool isFloat(unsigned Width) const {
|
||||||
return isFloat() && ElementBitwidth == Width;
|
return isFloat() && ElementBitwidth == Width;
|
||||||
}
|
}
|
||||||
|
bool isConstant() const { return IsConstant; }
|
||||||
bool isPointer() const { return IsPointer; }
|
bool isPointer() const { return IsPointer; }
|
||||||
|
unsigned getElementBitwidth() const { return ElementBitwidth; }
|
||||||
|
|
||||||
|
ScalarTypeKind getScalarType() const { return ScalarType; }
|
||||||
|
VScaleVal getScale() const { return Scale; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Verify RVV vector type and set Valid.
|
// Verify RVV vector type and set Valid.
|
||||||
@ -263,18 +273,6 @@ public:
|
|||||||
PrototypeDescriptor Proto);
|
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 {
|
enum PolicyScheme : uint8_t {
|
||||||
SchemeNone,
|
SchemeNone,
|
||||||
HasPassthruOperand,
|
HasPassthruOperand,
|
||||||
@ -302,7 +300,6 @@ private:
|
|||||||
// The types we use to obtain the specific LLVM intrinsic. They are index of
|
// The types we use to obtain the specific LLVM intrinsic. They are index of
|
||||||
// InputTypes. -1 means the return type.
|
// InputTypes. -1 means the return type.
|
||||||
std::vector<int64_t> IntrinsicTypes;
|
std::vector<int64_t> IntrinsicTypes;
|
||||||
RISCVPredefinedMacroT RISCVPredefinedMacros = 0;
|
|
||||||
unsigned NF = 1;
|
unsigned NF = 1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -333,9 +330,6 @@ public:
|
|||||||
llvm::StringRef getIRName() const { return IRName; }
|
llvm::StringRef getIRName() const { return IRName; }
|
||||||
llvm::StringRef getManualCodegen() const { return ManualCodegen; }
|
llvm::StringRef getManualCodegen() const { return ManualCodegen; }
|
||||||
PolicyScheme getPolicyScheme() const { return Scheme; }
|
PolicyScheme getPolicyScheme() const { return Scheme; }
|
||||||
RISCVPredefinedMacroT getRISCVPredefinedMacros() const {
|
|
||||||
return RISCVPredefinedMacros;
|
|
||||||
}
|
|
||||||
unsigned getNF() const { return NF; }
|
unsigned getNF() const { return NF; }
|
||||||
const std::vector<int64_t> &getIntrinsicTypes() const {
|
const std::vector<int64_t> &getIntrinsicTypes() const {
|
||||||
return IntrinsicTypes;
|
return IntrinsicTypes;
|
||||||
@ -349,6 +343,67 @@ public:
|
|||||||
llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors);
|
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 RISCV
|
||||||
|
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
@ -350,6 +350,16 @@ struct PragmaMaxTokensTotalHandler : public PragmaHandler {
|
|||||||
Token &FirstToken) override;
|
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) {
|
void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) {
|
||||||
for (auto &T : Toks)
|
for (auto &T : Toks)
|
||||||
T.setFlag(clang::Token::IsReinjected);
|
T.setFlag(clang::Token::IsReinjected);
|
||||||
@ -493,6 +503,11 @@ void Parser::initializePragmaHandlers() {
|
|||||||
|
|
||||||
MaxTokensTotalPragmaHandler = std::make_unique<PragmaMaxTokensTotalHandler>();
|
MaxTokensTotalPragmaHandler = std::make_unique<PragmaMaxTokensTotalHandler>();
|
||||||
PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
|
PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
|
||||||
|
|
||||||
|
if (getTargetInfo().getTriple().isRISCV()) {
|
||||||
|
RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>(Actions);
|
||||||
|
PP.AddPragmaHandler("clang", RISCVPragmaHandler.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::resetPragmaHandlers() {
|
void Parser::resetPragmaHandlers() {
|
||||||
@ -617,6 +632,11 @@ void Parser::resetPragmaHandlers() {
|
|||||||
|
|
||||||
PP.RemovePragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
|
PP.RemovePragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
|
||||||
MaxTokensTotalPragmaHandler.reset();
|
MaxTokensTotalPragmaHandler.reset();
|
||||||
|
|
||||||
|
if (getTargetInfo().getTriple().isRISCV()) {
|
||||||
|
PP.RemovePragmaHandler("clang", RISCVPragmaHandler.get());
|
||||||
|
RISCVPragmaHandler.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle the annotation token produced for #pragma unused(...)
|
/// Handle the annotation token produced for #pragma unused(...)
|
||||||
@ -3929,3 +3949,35 @@ void PragmaMaxTokensTotalHandler::HandlePragma(Preprocessor &PP,
|
|||||||
|
|
||||||
PP.overrideMaxTokens(MaxTokens, Loc);
|
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;
|
||||||
|
}
|
||||||
|
@ -52,6 +52,7 @@ add_clang_library(clangSema
|
|||||||
SemaOpenMP.cpp
|
SemaOpenMP.cpp
|
||||||
SemaOverload.cpp
|
SemaOverload.cpp
|
||||||
SemaPseudoObject.cpp
|
SemaPseudoObject.cpp
|
||||||
|
SemaRISCVVectorLookup.cpp
|
||||||
SemaStmt.cpp
|
SemaStmt.cpp
|
||||||
SemaStmtAsm.cpp
|
SemaStmtAsm.cpp
|
||||||
SemaStmtAttr.cpp
|
SemaStmtAttr.cpp
|
||||||
@ -74,4 +75,5 @@ add_clang_library(clangSema
|
|||||||
clangBasic
|
clangBasic
|
||||||
clangEdit
|
clangEdit
|
||||||
clangLex
|
clangLex
|
||||||
|
clangSupport
|
||||||
)
|
)
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "clang/Sema/Initialization.h"
|
#include "clang/Sema/Initialization.h"
|
||||||
#include "clang/Sema/MultiplexExternalSemaSource.h"
|
#include "clang/Sema/MultiplexExternalSemaSource.h"
|
||||||
#include "clang/Sema/ObjCMethodList.h"
|
#include "clang/Sema/ObjCMethodList.h"
|
||||||
|
#include "clang/Sema/RISCVIntrinsicManager.h"
|
||||||
#include "clang/Sema/Scope.h"
|
#include "clang/Sema/Scope.h"
|
||||||
#include "clang/Sema/ScopeInfo.h"
|
#include "clang/Sema/ScopeInfo.h"
|
||||||
#include "clang/Sema/SemaConsumer.h"
|
#include "clang/Sema/SemaConsumer.h"
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "clang/Sema/DeclSpec.h"
|
#include "clang/Sema/DeclSpec.h"
|
||||||
#include "clang/Sema/Lookup.h"
|
#include "clang/Sema/Lookup.h"
|
||||||
#include "clang/Sema/Overload.h"
|
#include "clang/Sema/Overload.h"
|
||||||
|
#include "clang/Sema/RISCVIntrinsicManager.h"
|
||||||
#include "clang/Sema/Scope.h"
|
#include "clang/Sema/Scope.h"
|
||||||
#include "clang/Sema/ScopeInfo.h"
|
#include "clang/Sema/ScopeInfo.h"
|
||||||
#include "clang/Sema/Sema.h"
|
#include "clang/Sema/Sema.h"
|
||||||
@ -928,6 +929,14 @@ bool Sema::LookupBuiltin(LookupResult &R) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 this is a builtin on this (or all) targets, create the decl.
|
||||||
if (unsigned BuiltinID = II->getBuiltinID()) {
|
if (unsigned BuiltinID = II->getBuiltinID()) {
|
||||||
// In C++, C2x, and OpenCL (spec v1.2 s6.9.f), we don't have any
|
// In C++, C2x, and OpenCL (spec v1.2 s6.9.f), we don't have any
|
||||||
|
386
clang/lib/Sema/SemaRISCVVectorLookup.cpp
Normal file
386
clang/lib/Sema/SemaRISCVVectorLookup.cpp
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
//==- 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
|
@ -873,27 +873,6 @@ RVVIntrinsic::RVVIntrinsic(
|
|||||||
Name += "_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
|
// Init OutputType and InputTypes
|
||||||
OutputType = OutInTypes[0];
|
OutputType = OutInTypes[0];
|
||||||
InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());
|
InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());
|
||||||
@ -951,5 +930,29 @@ SmallVector<PrototypeDescriptor> parsePrototypes(StringRef Prototypes) {
|
|||||||
return PrototypeDescriptors;
|
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 RISCV
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
22
clang/test/Sema/riscv-bad-intrinsic-pragma.c
Normal file
22
clang/test/Sema/riscv-bad-intrinsic-pragma.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// 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:
|
4
clang/test/Sema/riscv-intrinsic-pragma.c
Normal file
4
clang/test/Sema/riscv-intrinsic-pragma.c
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// RUN: %clang_cc1 -triple riscv64 -target-feature +v -emit-llvm -o - -verify %s
|
||||||
|
|
||||||
|
#pragma clang riscv intrinsic vector
|
||||||
|
// expected-no-diagnostics
|
@ -20,6 +20,7 @@
|
|||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
#include "llvm/ADT/StringSet.h"
|
#include "llvm/ADT/StringSet.h"
|
||||||
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
#include "llvm/ADT/Twine.h"
|
#include "llvm/ADT/Twine.h"
|
||||||
#include "llvm/TableGen/Error.h"
|
#include "llvm/TableGen/Error.h"
|
||||||
#include "llvm/TableGen/Record.h"
|
#include "llvm/TableGen/Record.h"
|
||||||
@ -29,6 +30,59 @@ using namespace llvm;
|
|||||||
using namespace clang::RISCV;
|
using namespace clang::RISCV;
|
||||||
|
|
||||||
namespace {
|
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 {
|
class RVVEmitter {
|
||||||
private:
|
private:
|
||||||
RecordKeeper &Records;
|
RecordKeeper &Records;
|
||||||
@ -45,22 +99,22 @@ public:
|
|||||||
/// Emit all the information needed to map builtin -> LLVM IR intrinsic.
|
/// Emit all the information needed to map builtin -> LLVM IR intrinsic.
|
||||||
void createCodeGen(raw_ostream &o);
|
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:
|
private:
|
||||||
/// Create all intrinsics and add them to \p Out
|
/// Create all intrinsics and add them to \p Out and SemaRecords.
|
||||||
void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out);
|
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
|
/// Print HeaderCode in RVVHeader Record to \p Out
|
||||||
void printHeaderCode(raw_ostream &OS);
|
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
|
} // namespace
|
||||||
@ -151,33 +205,83 @@ void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) {
|
|||||||
OS << " break;\n";
|
OS << " break;\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitIntrinsicFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) {
|
//===----------------------------------------------------------------------===//
|
||||||
OS << "__attribute__((__clang_builtin_alias__(";
|
// SemaSignatureTable implementation
|
||||||
OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n";
|
//===----------------------------------------------------------------------===//
|
||||||
OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getName() << "(";
|
void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) {
|
||||||
// Emit function arguments
|
// Sort signature entries by length, let longer signature insert first, to
|
||||||
const RVVTypes &InputTypes = RVVI.getInputTypes();
|
// make it more possible to reuse table entries, that can reduce ~10% table
|
||||||
if (!InputTypes.empty()) {
|
// size.
|
||||||
ListSeparator LS;
|
struct Compare {
|
||||||
for (unsigned i = 0; i < InputTypes.size(); ++i)
|
bool operator()(const SmallVector<PrototypeDescriptor> &A,
|
||||||
OS << LS << InputTypes[i]->getTypeStr();
|
const SmallVector<PrototypeDescriptor> &B) const {
|
||||||
}
|
if (A.size() != B.size())
|
||||||
OS << ");\n";
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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 emitOverloadedFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) {
|
void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) {
|
||||||
OS << "__attribute__((__clang_builtin_alias__(";
|
if (getIndex(Signature) != INVALID_INDEX)
|
||||||
OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n";
|
return;
|
||||||
OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getOverloadedName()
|
|
||||||
<< "(";
|
// Insert Signature into SignatureTable if not found in the table.
|
||||||
// Emit function arguments
|
SignatureTable.insert(SignatureTable.begin(), Signature.begin(),
|
||||||
const RVVTypes &InputTypes = RVVI.getInputTypes();
|
Signature.end());
|
||||||
if (!InputTypes.empty()) {
|
}
|
||||||
ListSeparator LS;
|
|
||||||
for (unsigned i = 0; i < InputTypes.size(); ++i)
|
unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) {
|
||||||
OS << LS << InputTypes[i]->getTypeStr();
|
// 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";
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -212,10 +316,9 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
|
|||||||
OS << "extern \"C\" {\n";
|
OS << "extern \"C\" {\n";
|
||||||
OS << "#endif\n\n";
|
OS << "#endif\n\n";
|
||||||
|
|
||||||
printHeaderCode(OS);
|
OS << "#pragma clang riscv intrinsic vector\n\n";
|
||||||
|
|
||||||
std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
|
printHeaderCode(OS);
|
||||||
createRVVIntrinsics(Defs);
|
|
||||||
|
|
||||||
auto printType = [&](auto T) {
|
auto printType = [&](auto T) {
|
||||||
OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
|
OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
|
||||||
@ -255,7 +358,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
|
|||||||
}
|
}
|
||||||
OS << "#endif\n";
|
OS << "#endif\n";
|
||||||
|
|
||||||
OS << "#if defined(__riscv_f)\n";
|
OS << "#if (__riscv_v_elen_fp >= 32)\n";
|
||||||
for (int Log2LMUL : Log2LMULs) {
|
for (int Log2LMUL : Log2LMULs) {
|
||||||
auto T = RVVType::computeType(BasicType::Float32, Log2LMUL,
|
auto T = RVVType::computeType(BasicType::Float32, Log2LMUL,
|
||||||
PrototypeDescriptor::Vector);
|
PrototypeDescriptor::Vector);
|
||||||
@ -264,7 +367,7 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
|
|||||||
}
|
}
|
||||||
OS << "#endif\n";
|
OS << "#endif\n";
|
||||||
|
|
||||||
OS << "#if defined(__riscv_d)\n";
|
OS << "#if (__riscv_v_elen_fp >= 64)\n";
|
||||||
for (int Log2LMUL : Log2LMULs) {
|
for (int Log2LMUL : Log2LMULs) {
|
||||||
auto T = RVVType::computeType(BasicType::Float64, Log2LMUL,
|
auto T = RVVType::computeType(BasicType::Float64, Log2LMUL,
|
||||||
PrototypeDescriptor::Vector);
|
PrototypeDescriptor::Vector);
|
||||||
@ -273,37 +376,8 @@ void RVVEmitter::createHeader(raw_ostream &OS) {
|
|||||||
}
|
}
|
||||||
OS << "#endif\n\n";
|
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";
|
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#ifdef __cplusplus\n";
|
||||||
OS << "}\n";
|
OS << "}\n";
|
||||||
OS << "#endif // __cplusplus\n";
|
OS << "#endif // __cplusplus\n";
|
||||||
@ -392,7 +466,8 @@ void RVVEmitter::createCodeGen(raw_ostream &OS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RVVEmitter::createRVVIntrinsics(
|
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");
|
std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin");
|
||||||
for (auto *R : RV) {
|
for (auto *R : RV) {
|
||||||
StringRef Name = R->getValueAsString("Name");
|
StringRef Name = R->getValueAsString("Name");
|
||||||
@ -502,6 +577,53 @@ void RVVEmitter::createRVVIntrinsics(
|
|||||||
}
|
}
|
||||||
} // end for Log2LMULList
|
} // end for Log2LMULList
|
||||||
} // end for TypeRange
|
} // 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,47 +636,60 @@ void RVVEmitter::printHeaderCode(raw_ostream &OS) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RVVEmitter::emitArchMacroAndBody(
|
void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
|
||||||
std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS,
|
SemaSignatureTable &SST,
|
||||||
std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) {
|
ArrayRef<SemaRecord> SemaRecords) {
|
||||||
RISCVPredefinedMacroT PrevMacros =
|
SST.init(SemaRecords);
|
||||||
(*Defs.begin())->getRISCVPredefinedMacros();
|
|
||||||
bool NeedEndif = emitMacroRestrictionStr(PrevMacros, OS);
|
for (const auto &SR : SemaRecords) {
|
||||||
for (auto &Def : Defs) {
|
Out.emplace_back(RVVIntrinsicRecord());
|
||||||
RISCVPredefinedMacroT CurMacros = Def->getRISCVPredefinedMacros();
|
RVVIntrinsicRecord &R = Out.back();
|
||||||
if (CurMacros != PrevMacros) {
|
R.Name = SR.Name.c_str();
|
||||||
if (NeedEndif)
|
R.OverloadedName = SR.OverloadedName.c_str();
|
||||||
OS << "#endif\n\n";
|
R.PrototypeIndex = SST.getIndex(SR.Prototype);
|
||||||
NeedEndif = emitMacroRestrictionStr(CurMacros, OS);
|
R.MaskedPrototypeIndex = SST.getIndex(SR.MaskedPrototype);
|
||||||
PrevMacros = CurMacros;
|
R.SuffixIndex = SST.getIndex(SR.Suffix);
|
||||||
}
|
R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix);
|
||||||
if (Def->hasBuiltinAlias())
|
R.PrototypeLength = SR.Prototype.size();
|
||||||
PrintBody(OS, *Def);
|
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,
|
void RVVEmitter::createSema(raw_ostream &OS) {
|
||||||
raw_ostream &OS) {
|
std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
|
||||||
if (PredefinedMacros == RISCVPredefinedMacro::Basic)
|
std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords;
|
||||||
return false;
|
SemaSignatureTable SST;
|
||||||
OS << "#if ";
|
std::vector<SemaRecord> SemaRecords;
|
||||||
ListSeparator LS(" && ");
|
|
||||||
if (PredefinedMacros & RISCVPredefinedMacro::V)
|
createRVVIntrinsics(Defs, &SemaRecords);
|
||||||
OS << LS << "defined(__riscv_v)";
|
|
||||||
if (PredefinedMacros & RISCVPredefinedMacro::Zvfh)
|
createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords);
|
||||||
OS << LS << "defined(__riscv_zvfh)";
|
|
||||||
if (PredefinedMacros & RISCVPredefinedMacro::RV64)
|
// Emit signature table for SemaRISCVVectorLookup.cpp.
|
||||||
OS << LS << "(__riscv_xlen == 64)";
|
OS << "#ifdef DECL_SIGNATURE_TABLE\n";
|
||||||
if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64)
|
SST.print(OS);
|
||||||
OS << LS << "(__riscv_v_elen >= 64)";
|
OS << "#endif\n";
|
||||||
if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp32)
|
|
||||||
OS << LS << "(__riscv_v_elen_fp >= 32)";
|
// Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp.
|
||||||
if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp64)
|
OS << "#ifdef DECL_INTRINSIC_RECORDS\n";
|
||||||
OS << LS << "(__riscv_v_elen_fp >= 64)";
|
for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords)
|
||||||
OS << "\n";
|
OS << Record;
|
||||||
return true;
|
OS << "#endif\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
@ -570,4 +705,8 @@ void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
|
|||||||
RVVEmitter(Records).createCodeGen(OS);
|
RVVEmitter(Records).createCodeGen(OS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) {
|
||||||
|
RVVEmitter(Records).createSema(OS);
|
||||||
|
}
|
||||||
|
|
||||||
} // End namespace clang
|
} // End namespace clang
|
||||||
|
@ -88,6 +88,7 @@ enum ActionType {
|
|||||||
GenRISCVVectorHeader,
|
GenRISCVVectorHeader,
|
||||||
GenRISCVVectorBuiltins,
|
GenRISCVVectorBuiltins,
|
||||||
GenRISCVVectorBuiltinCG,
|
GenRISCVVectorBuiltinCG,
|
||||||
|
GenRISCVVectorBuiltinSema,
|
||||||
GenAttrDocs,
|
GenAttrDocs,
|
||||||
GenDiagDocs,
|
GenDiagDocs,
|
||||||
GenOptDocs,
|
GenOptDocs,
|
||||||
@ -243,6 +244,8 @@ cl::opt<ActionType> Action(
|
|||||||
"Generate riscv_vector_builtins.inc for clang"),
|
"Generate riscv_vector_builtins.inc for clang"),
|
||||||
clEnumValN(GenRISCVVectorBuiltinCG, "gen-riscv-vector-builtin-codegen",
|
clEnumValN(GenRISCVVectorBuiltinCG, "gen-riscv-vector-builtin-codegen",
|
||||||
"Generate riscv_vector_builtin_cg.inc for clang"),
|
"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",
|
clEnumValN(GenAttrDocs, "gen-attr-docs",
|
||||||
"Generate attribute documentation"),
|
"Generate attribute documentation"),
|
||||||
clEnumValN(GenDiagDocs, "gen-diag-docs",
|
clEnumValN(GenDiagDocs, "gen-diag-docs",
|
||||||
@ -458,6 +461,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
|
|||||||
case GenRISCVVectorBuiltinCG:
|
case GenRISCVVectorBuiltinCG:
|
||||||
EmitRVVBuiltinCG(Records, OS);
|
EmitRVVBuiltinCG(Records, OS);
|
||||||
break;
|
break;
|
||||||
|
case GenRISCVVectorBuiltinSema:
|
||||||
|
EmitRVVBuiltinSema(Records, OS);
|
||||||
|
break;
|
||||||
case GenAttrDocs:
|
case GenAttrDocs:
|
||||||
EmitClangAttrDocs(Records, OS);
|
EmitClangAttrDocs(Records, OS);
|
||||||
break;
|
break;
|
||||||
|
@ -110,6 +110,7 @@ void EmitMveBuiltinAliases(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
|||||||
void EmitRVVHeader(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 EmitRVVBuiltins(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
||||||
void EmitRVVBuiltinCG(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 EmitCdeHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
||||||
void EmitCdeBuiltinDef(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
void EmitCdeBuiltinDef(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user