Introduce the implicit 'vk' namespace (#3133)
* [spirv] Introduce the implicit 'vk' namespace If any of these are used for DXIL code generation, the compiler will report an error about the unknown "vk" namespace. * [spirv] Introduce vk::ReadClock intrinsic. The following Vulkan specific intrinsic functions are added: ```hlsl uint64_t vk::ReadClock(in uint32 scope); ``` Also the following Vulkan-specific implicit constants are added: ``` vk::CrossDeviceScope; // defined as uint 0 vk::DeviceScope // defined as uint 1 vk::WorkgroupScope // defined as uint 2 vk::SubgroupScope // defined as uint 3 vk::InvocationScope // defined as uint 4 vk::QueueFamilyScope // defined as uint 5 ``` Sample usage looks as follows: ```hlsl uint64_t clock = vk::ReadClock(vk::WorkgroupScope); ``` If any of these are used for DXIL code generation, the compiler will report an error about the unknown "vk" namespace. * [spirv] Add documentation. * Address code review comments. * Test: Validate vk namespace is not allowed for dxil. * Fix usage of DXASSERT. * Move ValidateVkNamespaceNotAllowed test to HlslFileCheck.
This commit is contained in:
Родитель
a30d76ab78
Коммит
d7bb9ee170
|
@ -3552,6 +3552,79 @@ Quad ``QuadReadAcrossDiagonal()`` ``OpGroupNonUniformQuadSwap``
|
|||
Quad ``QuadReadLaneAt()`` ``OpGroupNonUniformQuadBroadcast``
|
||||
============= ============================ =================================== ======================
|
||||
|
||||
The Implicit ``vk`` Namespace
|
||||
=============================
|
||||
|
||||
Overview
|
||||
--------
|
||||
We have introduced an implicit namepace (called ``vk``) that will be home to all
|
||||
Vulkan-specific functions, enums, etc. Given the similarity between HLSL and
|
||||
C++, developers are likely familiar with namespaces -- and implicit namespaces
|
||||
(e.g. ``std::`` in C++). The ``vk`` namespace provides an interface for expressing
|
||||
Vulkan-specific features (core spec and KHR extensions).
|
||||
|
||||
**The compiler will generate the proper error message (** ``unknown 'vk' identifier`` **)
|
||||
if** ``vk::`` **is used for compiling to DXIL.**
|
||||
|
||||
Any intrinsic function or enum in the vk namespace will be deprecated if an
|
||||
equivalent one is added to the default namepsace.
|
||||
|
||||
Current Features
|
||||
----------------
|
||||
The following intrinsic functions and constants are currently defined in the
|
||||
implicit ``vk`` namepsace.
|
||||
|
||||
.. code:: hlsl
|
||||
|
||||
// Implicitly defined when compiling to SPIR-V.
|
||||
namespace vk {
|
||||
|
||||
const uint CrossDeviceScope = 0;
|
||||
const uint DeviceScope = 1;
|
||||
const uint WorkgroupScope = 2;
|
||||
const uint SubgroupScope = 3;
|
||||
const uint InvocationScope = 4;
|
||||
const uint QueueFamilyScope = 5;
|
||||
|
||||
uint64_t ReadClock(in uint scope);
|
||||
} // end namespace
|
||||
|
||||
|
||||
Intrinsic Constants
|
||||
-------------------
|
||||
The following constants are currently defined:
|
||||
|
||||
======================== ============================================
|
||||
Constant value (SPIR-V constant equivalent, if any)
|
||||
======================== ============================================
|
||||
``vk::CrossDeviceScope`` ``0`` (``CrossDevice``)
|
||||
``vk::DeviceScope`` ``1`` (``Device``)
|
||||
``vk::WorkgroupScope`` ``2`` (``Workgroup``)
|
||||
``vk::SubgroupScope`` ``3`` (``Subgroup``)
|
||||
``vk::InvocationScope`` ``4`` (``Invocation``)
|
||||
``vk::QueueFamilyScope`` ``5`` (``QueueFamily``)
|
||||
======================== ============================================
|
||||
|
||||
Intrinsic Functions
|
||||
-------------------
|
||||
|
||||
ReadClock
|
||||
~~~~~~~~~
|
||||
This intrinsic funcion has the following signature:
|
||||
|
||||
.. code:: hlsl
|
||||
|
||||
uint64_t ReadClock(in uint scope);
|
||||
|
||||
It translates to performing ``OpReadClockKHR`` defined in `VK_KHR_shader_clock <https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shader_clock.html>`_.
|
||||
One can use the predefined scopes in the ``vk`` namepsace to specify the scope argument.
|
||||
For example:
|
||||
|
||||
.. code:: hlsl
|
||||
|
||||
uint64_t clock = vk::ReadClock(vk::SubgroupScope);
|
||||
|
||||
|
||||
Supported Command-line Options
|
||||
==============================
|
||||
|
||||
|
|
|
@ -224,6 +224,9 @@ import hctdb_instrhelp
|
|||
IOP_texCUBEproj,
|
||||
IOP_transpose,
|
||||
IOP_trunc,
|
||||
#ifdef ENABLE_SPIRV_CODEGEN
|
||||
IOP_VkReadClock,
|
||||
#endif // ENABLE_SPIRV_CODEGEN
|
||||
MOP_Append,
|
||||
MOP_RestartStrip,
|
||||
MOP_CalculateLevelOfDetail,
|
||||
|
|
|
@ -5355,6 +5355,9 @@ IntrinsicLower gLowerTable[] = {
|
|||
{IntrinsicOp::IOP_texCUBEproj, EmptyLower, DXIL::OpCode::NumOpCodes},
|
||||
{IntrinsicOp::IOP_transpose, EmptyLower, DXIL::OpCode::NumOpCodes},
|
||||
{IntrinsicOp::IOP_trunc, TrivialUnaryOperation, DXIL::OpCode::Round_z},
|
||||
// SPIR-V Change Starts
|
||||
{IntrinsicOp::IOP_VkReadClock, UnsupportedVulkanIntrinsic, DXIL::OpCode::NumOpCodes},
|
||||
// SPIR-V Change Ends
|
||||
|
||||
{IntrinsicOp::MOP_Append, StreamOutputLower, DXIL::OpCode::EmitStream},
|
||||
{IntrinsicOp::MOP_RestartStrip, StreamOutputLower, DXIL::OpCode::CutStream},
|
||||
|
|
|
@ -36,6 +36,7 @@ enum class Extension {
|
|||
KHR_shader_draw_parameters,
|
||||
KHR_post_depth_coverage,
|
||||
KHR_ray_tracing,
|
||||
KHR_shader_clock,
|
||||
EXT_demote_to_helper_invocation,
|
||||
EXT_descriptor_indexing,
|
||||
EXT_fragment_fully_covered,
|
||||
|
|
|
@ -496,6 +496,8 @@ public:
|
|||
createRayQueryOpsKHR(spv::Op opcode, QualType resultType,
|
||||
llvm::ArrayRef<SpirvInstruction *> operands,
|
||||
bool cullFlags, SourceLocation loc);
|
||||
/// \brief Creates an OpReadClockKHR instruction.
|
||||
SpirvInstruction *createReadClock(SpirvInstruction *scope, SourceLocation);
|
||||
|
||||
// === SPIR-V Module Structure ===
|
||||
inline void setMemoryModel(spv::AddressingModel, spv::MemoryModel);
|
||||
|
|
|
@ -118,6 +118,7 @@ public:
|
|||
IK_Load, // OpLoad
|
||||
IK_RayQueryOpKHR, // KHR rayquery ops
|
||||
IK_RayTracingOpNV, // NV raytracing ops
|
||||
IK_ReadClock, // OpReadClock
|
||||
IK_SampledImage, // OpSampledImage
|
||||
IK_Select, // OpSelect
|
||||
IK_SpecConstantBinaryOp, // SpecConstant binary operations
|
||||
|
@ -2702,6 +2703,25 @@ private:
|
|||
SpirvDebugInfoNone *debugNone;
|
||||
};
|
||||
|
||||
class SpirvReadClock : public SpirvInstruction {
|
||||
public:
|
||||
SpirvReadClock(QualType resultType, SpirvInstruction *scope, SourceLocation);
|
||||
|
||||
DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvReadClock)
|
||||
|
||||
// For LLVM-style RTTI
|
||||
static bool classof(const SpirvInstruction *inst) {
|
||||
return inst->getKind() == IK_ReadClock;
|
||||
}
|
||||
|
||||
bool invokeVisitor(Visitor *v) override;
|
||||
|
||||
SpirvInstruction *getScope() const { return scope; }
|
||||
|
||||
private:
|
||||
SpirvInstruction *scope;
|
||||
};
|
||||
|
||||
#undef DECLARE_INVOKE_VISITOR_FOR_CLASS
|
||||
|
||||
} // namespace spirv
|
||||
|
|
|
@ -137,6 +137,8 @@ public:
|
|||
DEFINE_VISIT_METHOD(SpirvDebugTypeTemplateParameter)
|
||||
|
||||
DEFINE_VISIT_METHOD(SpirvRayQueryOpKHR)
|
||||
DEFINE_VISIT_METHOD(SpirvReadClock)
|
||||
|
||||
#undef DEFINE_VISIT_METHOD
|
||||
|
||||
protected:
|
||||
|
|
|
@ -605,6 +605,14 @@ bool CapabilityVisitor::visit(SpirvDemoteToHelperInvocationEXT *inst) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CapabilityVisitor::visit(SpirvReadClock *inst) {
|
||||
auto loc = inst->getSourceLocation();
|
||||
addCapabilityForType(inst->getResultType(), loc, inst->getStorageClass());
|
||||
addCapability(spv::Capability::ShaderClockKHR, loc);
|
||||
addExtension(Extension::KHR_shader_clock, "ReadClock", loc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CapabilityVisitor::visit(SpirvModule *, Visitor::Phase phase) {
|
||||
// If there are no entry-points in the module (hence shaderModel is not set),
|
||||
// add the Linkage capability. This allows library shader models to use
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
bool visit(SpirvExtInstImport *) override;
|
||||
bool visit(SpirvExtInst *) override;
|
||||
bool visit(SpirvDemoteToHelperInvocationEXT *) override;
|
||||
bool visit(SpirvReadClock *) override;
|
||||
|
||||
using Visitor::visit;
|
||||
|
||||
|
|
|
@ -1634,6 +1634,17 @@ bool EmitVisitor::visit(SpirvRayQueryOpKHR *inst) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool EmitVisitor::visit(SpirvReadClock *inst) {
|
||||
initInstruction(inst);
|
||||
curInst.push_back(inst->getResultTypeId());
|
||||
curInst.push_back(getOrAssignResultId<SpirvInstruction>(inst));
|
||||
curInst.push_back(getOrAssignResultId<SpirvInstruction>(inst->getScope()));
|
||||
finalizeInstruction(&mainBinary);
|
||||
emitDebugNameForInstruction(getOrAssignResultId<SpirvInstruction>(inst),
|
||||
inst->getDebugName());
|
||||
return true;
|
||||
}
|
||||
|
||||
// EmitTypeHandler ------
|
||||
|
||||
void EmitTypeHandler::initTypeInstruction(spv::Op op) {
|
||||
|
|
|
@ -266,6 +266,7 @@ public:
|
|||
bool visit(SpirvRayTracingOpNV *) override;
|
||||
bool visit(SpirvDemoteToHelperInvocationEXT *) override;
|
||||
bool visit(SpirvRayQueryOpKHR *) override;
|
||||
bool visit(SpirvReadClock *) override;
|
||||
|
||||
bool visit(SpirvDebugInfoNone *) override;
|
||||
bool visit(SpirvDebugSource *) override;
|
||||
|
|
|
@ -136,6 +136,7 @@ Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
|
|||
Extension::GOOGLE_hlsl_functionality1)
|
||||
.Case("SPV_GOOGLE_user_type", Extension::GOOGLE_user_type)
|
||||
.Case("SPV_KHR_post_depth_coverage", Extension::KHR_post_depth_coverage)
|
||||
.Case("SPV_KHR_shader_clock", Extension::KHR_shader_clock)
|
||||
.Case("SPV_NV_ray_tracing", Extension::NV_ray_tracing)
|
||||
.Case("SPV_NV_mesh_shader", Extension::NV_mesh_shader)
|
||||
.Case("SPV_KHR_ray_query", Extension::KHR_ray_query)
|
||||
|
@ -160,6 +161,8 @@ const char *FeatureManager::getExtensionName(Extension symbol) {
|
|||
return "SPV_KHR_post_depth_coverage";
|
||||
case Extension::KHR_ray_tracing:
|
||||
return "SPV_KHR_ray_tracing";
|
||||
case Extension::KHR_shader_clock:
|
||||
return "SPV_KHR_shader_clock";
|
||||
case Extension::EXT_demote_to_helper_invocation:
|
||||
return "SPV_EXT_demote_to_helper_invocation";
|
||||
case Extension::EXT_descriptor_indexing:
|
||||
|
|
|
@ -929,6 +929,16 @@ SpirvBuilder::createRayQueryOpsKHR(spv::Op opcode, QualType resultType,
|
|||
return inst;
|
||||
}
|
||||
|
||||
SpirvInstruction *SpirvBuilder::createReadClock(SpirvInstruction *scope,
|
||||
SourceLocation loc) {
|
||||
assert(insertPoint && "null insert point");
|
||||
assert(scope->getAstResultType()->isIntegerType());
|
||||
auto *inst =
|
||||
new (context) SpirvReadClock(astContext.UnsignedLongLongTy, scope, loc);
|
||||
insertPoint->addInstruction(inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
void SpirvBuilder::addModuleProcessed(llvm::StringRef process) {
|
||||
mod->addModuleProcessed(new (context) SpirvModuleProcessed({}, process));
|
||||
}
|
||||
|
|
|
@ -38,6 +38,24 @@ namespace spirv {
|
|||
|
||||
namespace {
|
||||
|
||||
// Returns true if the given decl is an implicit variable declaration inside the
|
||||
// "vk" namespace.
|
||||
bool isImplicitVarDeclInVkNamespace(const Decl *decl) {
|
||||
if (!decl)
|
||||
return false;
|
||||
|
||||
if (auto *varDecl = dyn_cast<VarDecl>(decl)) {
|
||||
// Check whether it is implicitly defined.
|
||||
if (!decl->isImplicit())
|
||||
return false;
|
||||
|
||||
if (auto *nsDecl = dyn_cast<NamespaceDecl>(varDecl->getDeclContext()))
|
||||
if (nsDecl->getName().equals("vk"))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if the given decl has the given semantic.
|
||||
bool hasSemantic(const DeclaratorDecl *decl,
|
||||
hlsl::DXIL::SemanticKind semanticKind) {
|
||||
|
@ -809,8 +827,12 @@ SpirvInstruction *SpirvEmitter::doExpr(const Expr *expr) {
|
|||
expr = expr->IgnoreParens();
|
||||
|
||||
if (const auto *declRefExpr = dyn_cast<DeclRefExpr>(expr)) {
|
||||
result = declIdMapper.getDeclEvalInfo(declRefExpr->getDecl(),
|
||||
expr->getLocStart());
|
||||
auto *decl = declRefExpr->getDecl();
|
||||
if (isImplicitVarDeclInVkNamespace(declRefExpr->getDecl())) {
|
||||
result = doExpr(cast<VarDecl>(decl)->getInit());
|
||||
} else {
|
||||
result = declIdMapper.getDeclEvalInfo(decl, expr->getLocStart());
|
||||
}
|
||||
} else if (const auto *memberExpr = dyn_cast<MemberExpr>(expr)) {
|
||||
result = doMemberExpr(memberExpr);
|
||||
} else if (const auto *castExpr = dyn_cast<CastExpr>(expr)) {
|
||||
|
@ -7312,6 +7334,9 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
|
|||
case hlsl::IntrinsicOp::IOP_rcp:
|
||||
retVal = processIntrinsicRcp(callExpr);
|
||||
break;
|
||||
case hlsl::IntrinsicOp::IOP_VkReadClock:
|
||||
retVal = processIntrinsicReadClock(callExpr);
|
||||
break;
|
||||
case hlsl::IntrinsicOp::IOP_saturate:
|
||||
retVal = processIntrinsicSaturate(callExpr);
|
||||
break;
|
||||
|
@ -9199,6 +9224,13 @@ SpirvInstruction *SpirvEmitter::processIntrinsicRcp(const CallExpr *callExpr) {
|
|||
getValueOne(argType), argId, loc);
|
||||
}
|
||||
|
||||
SpirvInstruction *
|
||||
SpirvEmitter::processIntrinsicReadClock(const CallExpr *callExpr) {
|
||||
auto *scope = doExpr(callExpr->getArg(0));
|
||||
assert(scope->getAstResultType()->isIntegerType());
|
||||
return spvBuilder.createReadClock(scope, callExpr->getExprLoc());
|
||||
}
|
||||
|
||||
SpirvInstruction *
|
||||
SpirvEmitter::processIntrinsicAllOrAny(const CallExpr *callExpr,
|
||||
spv::Op spvOp) {
|
||||
|
|
|
@ -488,6 +488,9 @@ private:
|
|||
/// Processes the 'rcp' intrinsic function.
|
||||
SpirvInstruction *processIntrinsicRcp(const CallExpr *);
|
||||
|
||||
/// Processes the 'ReadClock' intrinsic function.
|
||||
SpirvInstruction *processIntrinsicReadClock(const CallExpr *);
|
||||
|
||||
/// Processes the 'sign' intrinsic function for float types.
|
||||
/// The FSign instruction in the GLSL instruction set returns a floating point
|
||||
/// result. The HLSL sign function, however, returns an integer. An extra
|
||||
|
|
|
@ -104,6 +104,7 @@ DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugTypeMember)
|
|||
DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugTypeTemplate)
|
||||
DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvDebugTypeTemplateParameter)
|
||||
DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvRayQueryOpKHR)
|
||||
DEFINE_INVOKE_VISITOR_FOR_CLASS(SpirvReadClock)
|
||||
|
||||
#undef DEFINE_INVOKE_VISITOR_FOR_CLASS
|
||||
|
||||
|
@ -981,5 +982,10 @@ SpirvRayQueryOpKHR::SpirvRayQueryOpKHR(
|
|||
: SpirvInstruction(IK_RayQueryOpKHR, opcode, resultType, loc),
|
||||
operands(vecOperands.begin(), vecOperands.end()), cullFlags(flags) {}
|
||||
|
||||
SpirvReadClock::SpirvReadClock(QualType resultType, SpirvInstruction *s,
|
||||
SourceLocation loc)
|
||||
: SpirvInstruction(IK_ReadClock, spv::Op::OpReadClockKHR, resultType, loc),
|
||||
scope(s) {}
|
||||
|
||||
} // namespace spirv
|
||||
} // namespace clang
|
||||
|
|
|
@ -2739,8 +2739,17 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
|
|||
return false;
|
||||
|
||||
// Never if a scope specifier was provided.
|
||||
if (SS.isSet())
|
||||
return false;
|
||||
if (SS.isSet()) {
|
||||
// HLSL Change begins
|
||||
// We want to be able to have intrinsics inside the "vk" namespace.
|
||||
const bool isVkNamespace =
|
||||
SS.getScopeRep() && SS.getScopeRep()->getAsNamespace() &&
|
||||
SS.getScopeRep()->getAsNamespace()->getName() == "vk";
|
||||
|
||||
if (!isVkNamespace)
|
||||
// HLSL Change ends
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only in C++ or ObjC++.
|
||||
if (!getLangOpts().CPlusPlus)
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "dxc/dxcapi.internal.h"
|
||||
#include "dxc/HlslIntrinsicOp.h"
|
||||
#include "gen_intrin_main_tables_15.h"
|
||||
#include "VkConstantsTables.h"
|
||||
#include "dxc/HLSL/HLOperations.h"
|
||||
#include "dxc/DXIL/DxilShaderModel.h"
|
||||
#include <array>
|
||||
|
@ -2914,8 +2915,12 @@ private:
|
|||
// Declaration for matrix and vector templates.
|
||||
ClassTemplateDecl* m_matrixTemplateDecl;
|
||||
ClassTemplateDecl* m_vectorTemplateDecl;
|
||||
// Namespace decl for hlsl intrin functions
|
||||
// Namespace decl for hlsl intrinsic functions
|
||||
NamespaceDecl* m_hlslNSDecl;
|
||||
|
||||
// Namespace decl for Vulkan-specific intrinsic functions
|
||||
NamespaceDecl* m_vkNSDecl;
|
||||
|
||||
// Context being processed.
|
||||
_Notnull_ ASTContext* m_context;
|
||||
|
||||
|
@ -3340,6 +3345,61 @@ private:
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Adds intrinsic function declarations to the "vk" namespace.
|
||||
// It does so only if SPIR-V code generation is being done.
|
||||
// Assumes the implicit "vk" namespace has already been created.
|
||||
void AddVkIntrinsicFunctions() {
|
||||
// If not doing SPIR-V CodeGen, return.
|
||||
if (!m_sema->getLangOpts().SPIRV)
|
||||
return;
|
||||
|
||||
DXASSERT(m_vkNSDecl, "caller has not created the vk namespace yet");
|
||||
|
||||
auto &context = m_sema->getASTContext();
|
||||
for (uint32_t i = 0; i < _countof(g_VkIntrinsics); ++i) {
|
||||
const HLSL_INTRINSIC *intrinsic = &g_VkIntrinsics[i];
|
||||
const IdentifierInfo &fnII = context.Idents.get(
|
||||
intrinsic->pArgs->pName, tok::TokenKind::identifier);
|
||||
DeclarationName functionName(&fnII);
|
||||
FunctionDecl *functionDecl = FunctionDecl::Create(
|
||||
context, m_vkNSDecl, NoLoc, DeclarationNameInfo(functionName, NoLoc),
|
||||
/*functionType*/ {}, nullptr, StorageClass::SC_Extern,
|
||||
InlineSpecifiedFalse, HasWrittenPrototypeTrue);
|
||||
m_vkNSDecl->addDecl(functionDecl);
|
||||
functionDecl->setLexicalDeclContext(m_vkNSDecl);
|
||||
functionDecl->setDeclContext(m_vkNSDecl);
|
||||
functionDecl->setImplicit(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds implicitly defined Vulkan-specific constants to the "vk" namespace.
|
||||
// It does so only if SPIR-V code generation is being done.
|
||||
// Assumes the implicit "vk" namespace has already been created.
|
||||
void AddVkIntrinsicConstants() {
|
||||
// If not doing SPIR-V CodeGen, return.
|
||||
if (!m_sema->getLangOpts().SPIRV)
|
||||
return;
|
||||
|
||||
DXASSERT(m_vkNSDecl, "caller has not created the vk namespace yet");
|
||||
|
||||
for (auto intConst : GetVkIntegerConstants()) {
|
||||
const llvm::StringRef name = intConst.first;
|
||||
const uint32_t value = intConst.second;
|
||||
auto &context = m_sema->getASTContext();
|
||||
QualType type = context.getConstType(context.UnsignedIntTy);
|
||||
IdentifierInfo &Id = context.Idents.get(name, tok::TokenKind::identifier);
|
||||
VarDecl *varDecl =
|
||||
VarDecl::Create(context, m_vkNSDecl, NoLoc, NoLoc, &Id, type,
|
||||
context.getTrivialTypeSourceInfo(type),
|
||||
clang::StorageClass::SC_Static);
|
||||
Expr *exprVal = IntegerLiteral::Create(
|
||||
context, llvm::APInt(context.getIntWidth(type), value), type, NoLoc);
|
||||
varDecl->setInit(exprVal);
|
||||
varDecl->setImplicit(true);
|
||||
m_vkNSDecl->addDecl(varDecl);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds all built-in HLSL object types.
|
||||
void AddObjectTypes()
|
||||
{
|
||||
|
@ -3504,6 +3564,8 @@ public:
|
|||
HLSLExternalSource() :
|
||||
m_matrixTemplateDecl(nullptr),
|
||||
m_vectorTemplateDecl(nullptr),
|
||||
m_hlslNSDecl(nullptr),
|
||||
m_vkNSDecl(nullptr),
|
||||
m_context(nullptr),
|
||||
m_sema(nullptr),
|
||||
m_hlslStringTypedef(nullptr)
|
||||
|
@ -3532,14 +3594,29 @@ public:
|
|||
|
||||
void InitializeSema(Sema& S) override
|
||||
{
|
||||
auto &context = S.getASTContext();
|
||||
m_sema = &S;
|
||||
S.addExternalSource(this);
|
||||
|
||||
AddObjectTypes();
|
||||
AddStdIsEqualImplementation(S.getASTContext(), S);
|
||||
AddStdIsEqualImplementation(context, S);
|
||||
for (auto && intrinsic : m_intrinsicTables) {
|
||||
AddIntrinsicTableMethods(intrinsic);
|
||||
}
|
||||
|
||||
if (m_sema->getLangOpts().SPIRV) {
|
||||
// Create the "vk" namespace which contains Vulkan-specific intrinsics.
|
||||
m_vkNSDecl =
|
||||
NamespaceDecl::Create(context, context.getTranslationUnitDecl(),
|
||||
/*Inline*/ false, SourceLocation(),
|
||||
SourceLocation(), &context.Idents.get("vk"),
|
||||
/*PrevDecl*/ nullptr);
|
||||
context.getTranslationUnitDecl()->addDecl(m_vkNSDecl);
|
||||
|
||||
// Add Vulkan-specific intrinsics.
|
||||
AddVkIntrinsicFunctions();
|
||||
AddVkIntrinsicConstants();
|
||||
}
|
||||
}
|
||||
|
||||
void ForgetSema() override
|
||||
|
@ -4271,9 +4348,21 @@ public:
|
|||
{
|
||||
DXASSERT_NOMSG(ULE != nullptr);
|
||||
|
||||
const bool isQualified = ULE->getQualifier();
|
||||
|
||||
const bool isGlobalNamespace =
|
||||
ULE->getQualifier() &&
|
||||
ULE->getQualifier()->getKind() == NestedNameSpecifier::Global;
|
||||
|
||||
const bool isVkNamespace =
|
||||
ULE->getQualifier() &&
|
||||
ULE->getQualifier()->getKind() == NestedNameSpecifier::Namespace &&
|
||||
ULE->getQualifier()->getAsNamespace()->getName() == "vk";
|
||||
|
||||
// Intrinsics live in the global namespace, so references to their names
|
||||
// should be either unqualified or '::'-prefixed.
|
||||
if (ULE->getQualifier() && ULE->getQualifier()->getKind() != NestedNameSpecifier::Global) {
|
||||
// Exception: Vulkan-specific intrinsics live in the 'vk::' namespace.
|
||||
if (isQualified && !isGlobalNamespace && !isVkNamespace) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4285,11 +4374,18 @@ public:
|
|||
}
|
||||
|
||||
StringRef nameIdentifier = idInfo->getName();
|
||||
const HLSL_INTRINSIC *table = g_Intrinsics;
|
||||
auto tableCount = _countof(g_Intrinsics);
|
||||
if (isVkNamespace) {
|
||||
table = g_VkIntrinsics;
|
||||
tableCount = _countof(g_VkIntrinsics);
|
||||
}
|
||||
|
||||
IntrinsicDefIter cursor = FindIntrinsicByNameAndArgCount(
|
||||
g_Intrinsics, _countof(g_Intrinsics), StringRef(), nameIdentifier, Args.size());
|
||||
table, tableCount, StringRef(), nameIdentifier, Args.size());
|
||||
IntrinsicDefIter end = IntrinsicDefIter::CreateEnd(
|
||||
g_Intrinsics, _countof(g_Intrinsics), IntrinsicTableDefIter::CreateEnd(m_intrinsicTables));
|
||||
table, tableCount, IntrinsicTableDefIter::CreateEnd(m_intrinsicTables));
|
||||
|
||||
for (;cursor != end; ++cursor)
|
||||
{
|
||||
// If this is the intrinsic we're interested in, build up a representation
|
||||
|
@ -4315,7 +4411,9 @@ public:
|
|||
if (insertedNewValue)
|
||||
{
|
||||
DXASSERT(tableName, "otherwise IDxcIntrinsicTable::GetTableName() failed");
|
||||
intrinsicFuncDecl = AddHLSLIntrinsicFunction(*m_context, m_hlslNSDecl, tableName, lowering, pIntrinsic, &functionArgTypes);
|
||||
intrinsicFuncDecl = AddHLSLIntrinsicFunction(
|
||||
*m_context, isVkNamespace ? m_vkNSDecl : m_hlslNSDecl, tableName,
|
||||
lowering, pIntrinsic, &functionArgTypes);
|
||||
insertResult.first->setFunctionDecl(intrinsicFuncDecl);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -10914,7 +10914,18 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
|
|||
#ifndef NDEBUG
|
||||
if (ULE->requiresADL()) {
|
||||
// To do ADL, we must have found an unqualified name.
|
||||
assert(!ULE->getQualifier() && "qualified name with ADL");
|
||||
// HLSL Change Begins
|
||||
//
|
||||
// We do want to allow argument-dependent lookup for intrinsic
|
||||
// function names inside the "vk" namespace (which are by definition
|
||||
// qualified names).
|
||||
bool isVkNamespace =
|
||||
ULE->getQualifier() &&
|
||||
ULE->getQualifier()->getKind() == NestedNameSpecifier::Namespace &&
|
||||
ULE->getQualifier()->getAsNamespace()->getName() == "vk";
|
||||
|
||||
assert((!ULE->getQualifier() || isVkNamespace) && "non-vk qualified name with ADL");
|
||||
// HLSL Change Ends
|
||||
|
||||
// We don't perform ADL for implicit declarations of builtins.
|
||||
// Verify that this was correctly set up.
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
//===--- VkConstantsTables.h --- Implict Vulkan Constants Tables ---C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains information about implictly-defined vulkan constants.
|
||||
// These constants will be added to the AST under the "vk" namespace.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIB_SEMA_VKCONSTANTSTABLES_H
|
||||
#define LLVM_CLANG_LIB_SEMA_VKCONSTANTSTABLES_H
|
||||
|
||||
std::vector<std::pair<std::string, uint32_t>> GetVkIntegerConstants() {
|
||||
return {
|
||||
{"CrossDeviceScope", 0u},
|
||||
{"DeviceScope", 1u},
|
||||
{"WorkgroupScope", 2u},
|
||||
{"SubgroupScope", 3u},
|
||||
{"InvocationScope", 4u},
|
||||
{"QueueFamilyScope", 5u},
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LLVM_CLANG_LIB_SEMA_VKCONSTANTSTABLES_H
|
|
@ -1724,6 +1724,25 @@ static const HLSL_INTRINSIC g_Intrinsics[] =
|
|||
{(UINT)hlsl::IntrinsicOp::IOP_trunc, false, true, false, -1, 2, g_Intrinsics_Args221},
|
||||
};
|
||||
|
||||
//
|
||||
// Start of VkIntrinsics
|
||||
//
|
||||
|
||||
#ifdef ENABLE_SPIRV_CODEGEN
|
||||
|
||||
static const HLSL_INTRINSIC_ARGUMENT g_VkIntrinsics_Args0[] =
|
||||
{
|
||||
{"ReadClock", AR_QUAL_OUT, 0, LITEMPLATE_SCALAR, 0, LICOMPTYPE_UINT64, 1, 1},
|
||||
{"scope", AR_QUAL_IN, 1, LITEMPLATE_SCALAR, 1, LICOMPTYPE_UINT, 1, 1},
|
||||
};
|
||||
|
||||
static const HLSL_INTRINSIC g_VkIntrinsics[] =
|
||||
{
|
||||
{(UINT)hlsl::IntrinsicOp::IOP_VkReadClock, false, false, false, -1, 2, g_VkIntrinsics_Args0},
|
||||
};
|
||||
|
||||
#endif // ENABLE_SPIRV_CODEGEN
|
||||
|
||||
//
|
||||
// Start of StreamMethods
|
||||
//
|
||||
|
@ -6315,6 +6334,7 @@ static const UINT g_uTexture2DMethodsCount = 77;
|
|||
static const UINT g_uTexture3DMethodsCount = 24;
|
||||
static const UINT g_uTextureCUBEArrayMethodsCount = 42;
|
||||
static const UINT g_uTextureCUBEMethodsCount = 42;
|
||||
static const UINT g_uVkIntrinsicsCount = 1;
|
||||
static const UINT g_uVkSubpassInputMSMethodsCount = 1;
|
||||
static const UINT g_uVkSubpassInputMethodsCount = 1;
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// Run: %dxc -T vs_6_0 -E main
|
||||
|
||||
struct SInstanceData {
|
||||
float4x3 VisualToWorld;
|
||||
float4 Output;
|
||||
};
|
||||
|
||||
struct VS_INPUT {
|
||||
float3 Position : POSITION;
|
||||
SInstanceData InstanceData : TEXCOORD4;
|
||||
};
|
||||
|
||||
float4 main(const VS_INPUT v) : SV_Position {
|
||||
const SInstanceData I = v.InstanceData;
|
||||
|
||||
// CHECK: OpStore %scope %uint_0
|
||||
uint32_t scope = vk::CrossDeviceScope;
|
||||
|
||||
return I.Output;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Run: %dxc -T vs_6_0 -E main
|
||||
|
||||
struct SInstanceData {
|
||||
float4x3 VisualToWorld;
|
||||
float4 Output;
|
||||
};
|
||||
|
||||
struct VS_INPUT {
|
||||
float3 Position : POSITION;
|
||||
SInstanceData InstanceData : TEXCOORD4;
|
||||
};
|
||||
|
||||
float4 main(const VS_INPUT v) : SV_Position {
|
||||
const SInstanceData I = v.InstanceData;
|
||||
|
||||
// CHECK: OpStore %scope %uint_1
|
||||
uint32_t scope = vk::DeviceScope;
|
||||
|
||||
return I.Output;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Run: %dxc -T vs_6_0 -E main
|
||||
|
||||
struct SInstanceData {
|
||||
float4x3 VisualToWorld;
|
||||
float4 Output;
|
||||
};
|
||||
|
||||
struct VS_INPUT {
|
||||
float3 Position : POSITION;
|
||||
SInstanceData InstanceData : TEXCOORD4;
|
||||
};
|
||||
|
||||
float4 main(const VS_INPUT v) : SV_Position {
|
||||
const SInstanceData I = v.InstanceData;
|
||||
|
||||
// CHECK: OpStore %scope %uint_4
|
||||
uint32_t scope = vk::InvocationScope;
|
||||
|
||||
return I.Output;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Run: %dxc -T vs_6_0 -E main
|
||||
|
||||
struct SInstanceData {
|
||||
float4x3 VisualToWorld;
|
||||
float4 Output;
|
||||
};
|
||||
|
||||
struct VS_INPUT {
|
||||
float3 Position : POSITION;
|
||||
SInstanceData InstanceData : TEXCOORD4;
|
||||
};
|
||||
|
||||
float4 main(const VS_INPUT v) : SV_Position {
|
||||
const SInstanceData I = v.InstanceData;
|
||||
|
||||
// CHECK: OpStore %scope %uint_5
|
||||
uint32_t scope = vk::QueueFamilyScope;
|
||||
|
||||
return I.Output;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Run: %dxc -T vs_6_0 -E main
|
||||
|
||||
// CHECK: OpCapability ShaderClockKHR
|
||||
// CHECK: OpExtension "SPV_KHR_shader_clock"
|
||||
|
||||
struct SInstanceData {
|
||||
float4x3 VisualToWorld;
|
||||
float4 Output;
|
||||
};
|
||||
|
||||
struct VS_INPUT {
|
||||
float3 Position : POSITION;
|
||||
SInstanceData InstanceData : TEXCOORD4;
|
||||
};
|
||||
|
||||
float4 main(const VS_INPUT v) : SV_Position {
|
||||
const SInstanceData I = v.InstanceData;
|
||||
uint64_t clock;
|
||||
// CHECK: {{%\d+}} = OpReadClockKHR %ulong %uint_1
|
||||
clock = vk::ReadClock(vk::DeviceScope);
|
||||
// CHECK: {{%\d+}} = OpReadClockKHR %ulong %uint_3
|
||||
clock = vk::ReadClock(vk::SubgroupScope);
|
||||
return I.Output;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Run: %dxc -T vs_6_0 -E main
|
||||
|
||||
struct SInstanceData {
|
||||
float4x3 VisualToWorld;
|
||||
float4 Output;
|
||||
};
|
||||
|
||||
struct VS_INPUT {
|
||||
float3 Position : POSITION;
|
||||
SInstanceData InstanceData : TEXCOORD4;
|
||||
};
|
||||
|
||||
float4 main(const VS_INPUT v) : SV_Position {
|
||||
const SInstanceData I = v.InstanceData;
|
||||
|
||||
// CHECK: OpStore %scope %uint_3
|
||||
uint32_t scope = vk::SubgroupScope;
|
||||
|
||||
return I.Output;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Run: %dxc -T vs_6_0 -E main
|
||||
|
||||
struct SInstanceData {
|
||||
float4x3 VisualToWorld;
|
||||
float4 Output;
|
||||
};
|
||||
|
||||
struct VS_INPUT {
|
||||
float3 Position : POSITION;
|
||||
SInstanceData InstanceData : TEXCOORD4;
|
||||
};
|
||||
|
||||
float4 main(const VS_INPUT v) : SV_Position {
|
||||
const SInstanceData I = v.InstanceData;
|
||||
|
||||
// CHECK: OpStore %scope %uint_2
|
||||
uint32_t scope = vk::WorkgroupScope;
|
||||
|
||||
return I.Output;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// RUN: %dxc -E main -T vs_6_0 %s | FileCheck %s
|
||||
|
||||
struct SInstanceData {
|
||||
float4x3 VisualToWorld;
|
||||
float4 Output;
|
||||
};
|
||||
|
||||
struct VS_INPUT {
|
||||
float3 Position : POSITION;
|
||||
SInstanceData InstanceData : TEXCOORD4;
|
||||
};
|
||||
|
||||
float4 main(const VS_INPUT v) : SV_Position {
|
||||
const SInstanceData I = v.InstanceData;
|
||||
uint64_t clock;
|
||||
// CHECK: error: use of undeclared identifier 'vk'
|
||||
clock = vk::ReadClock(vk::DeviceScope);
|
||||
// CHECK: error: use of undeclared identifier 'vk'
|
||||
clock = vk::ReadClock(vk::SubgroupScope);
|
||||
return I.Output;
|
||||
}
|
|
@ -1234,6 +1234,29 @@ TEST_F(FileTest, IntrinsicsMultiPrefix) {
|
|||
runFileTest("intrinsics.multiprefix.hlsl", Expect::Failure);
|
||||
}
|
||||
|
||||
// Vulkan-specific intrinsic functions
|
||||
TEST_F(FileTest, IntrinsicsVkCrossDeviceScope) {
|
||||
runFileTest("intrinsics.vkcrossdevicescope.hlsl");
|
||||
}
|
||||
TEST_F(FileTest, IntrinsicsVkDeviceScope) {
|
||||
runFileTest("intrinsics.vkdevicescope.hlsl");
|
||||
}
|
||||
TEST_F(FileTest, IntrinsicsVkWorkgroupScope) {
|
||||
runFileTest("intrinsics.vkworkgroupscope.hlsl");
|
||||
}
|
||||
TEST_F(FileTest, IntrinsicsVkSubgroupScope) {
|
||||
runFileTest("intrinsics.vksubgroupscope.hlsl");
|
||||
}
|
||||
TEST_F(FileTest, IntrinsicsVkInvocationScope) {
|
||||
runFileTest("intrinsics.vkinvocationscope.hlsl");
|
||||
}
|
||||
TEST_F(FileTest, IntrinsicsVkQueueFamilyScope) {
|
||||
runFileTest("intrinsics.vkqueuefamilyscope.hlsl");
|
||||
}
|
||||
TEST_F(FileTest, IntrinsicsVkReadClock) {
|
||||
runFileTest("intrinsics.vkreadclock.hlsl");
|
||||
}
|
||||
|
||||
// For attributes
|
||||
TEST_F(FileTest, AttributeEarlyDepthStencil) {
|
||||
runFileTest("attribute.earlydepthstencil.ps.hlsl");
|
||||
|
|
|
@ -330,6 +330,15 @@ resource [[rn]] CreateResourceFromHeap(in uint index);
|
|||
|
||||
} namespace
|
||||
|
||||
|
||||
// SPIRV Change Starts
|
||||
namespace VkIntrinsics {
|
||||
|
||||
u64 [[]] ReadClock(in uint scope);
|
||||
|
||||
} namespace
|
||||
// SPIRV Change Ends
|
||||
|
||||
namespace StreamMethods {
|
||||
|
||||
void [[]] Append(in $match<-1, 1> void x) : stream_append;
|
||||
|
|
|
@ -2742,6 +2742,12 @@ class db_hlsl_intrinsic(object):
|
|||
self.ns_idx = ns_idx # Namespace index
|
||||
self.doc = doc # Documentation
|
||||
id_prefix = "IOP" if ns == "Intrinsics" else "MOP"
|
||||
# SPIR-V Change Starts
|
||||
if ns == "VkIntrinsics":
|
||||
name = "Vk" + name
|
||||
self.name = "Vk" + self.name
|
||||
id_prefix = "IOP"
|
||||
# SPIR-V Change Ends
|
||||
self.enum_name = "%s_%s" % (id_prefix, name) # enum name
|
||||
self.readonly = ro # Only read memory
|
||||
self.readnone = rn # Not read memory
|
||||
|
|
|
@ -676,7 +676,7 @@ def get_hlsl_intrinsics():
|
|||
for i in sorted(db.intrinsics, key=lambda x: x.key):
|
||||
if last_ns != i.ns:
|
||||
last_ns = i.ns
|
||||
id_prefix = "IOP" if last_ns == "Intrinsics" else "MOP"
|
||||
id_prefix = "IOP" if last_ns == "Intrinsics" or last_ns == "VkIntrinsics" else "MOP" # SPIRV Change
|
||||
if (len(ns_table)):
|
||||
result += ns_table + "};\n"
|
||||
# SPIRV Change Starts
|
||||
|
|
Загрузка…
Ссылка в новой задаче