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:
Ehsan 2020-12-01 14:04:14 -06:00 коммит произвёл GitHub
Родитель a30d76ab78
Коммит d7bb9ee170
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
33 изменённых файлов: 567 добавлений и 12 удалений

Просмотреть файл

@ -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