Support space-only resource register annotations (#2163)
This change adds support for : register(spaceN), where a space is specified but no register, such that the resource allocator runs on the given space. For backwards compatibility, -auto-binding-space applies to resources without register bindings but not to those with an explicit register assignment like : register(t0) - those always go in space 0. To support this, I had to add state to represent "unspecified space". In the UnusualAnnotation, it's a Optional<uint32_t>. In the DxilResource, it's UINT_MAX, like we do for unspecified registers.
This commit is contained in:
Родитель
f89e3b7150
Коммит
17624a864b
|
@ -168,22 +168,21 @@ private:
|
|||
}
|
||||
|
||||
// Allocate unallocated resources
|
||||
const unsigned space = AutoBindingSpace;
|
||||
typename SpacesAllocator<unsigned, T>::Allocator &alloc0 = SAlloc.Get(space);
|
||||
typename SpacesAllocator<unsigned, T>::Allocator &reservedAlloc0 = ReservedRegisters.Get(space);
|
||||
for (auto &res : resourceList) {
|
||||
if (res->IsAllocated())
|
||||
continue;
|
||||
|
||||
DXASSERT(res->GetSpaceID() == 0,
|
||||
"otherwise non-zero space has no user register assignment");
|
||||
unsigned space = res->GetSpaceID();
|
||||
if (space == UINT_MAX) space = AutoBindingSpace;
|
||||
typename SpacesAllocator<unsigned, T>::Allocator& alloc = SAlloc.Get(space);
|
||||
typename SpacesAllocator<unsigned, T>::Allocator& reservedAlloc = ReservedRegisters.Get(space);
|
||||
|
||||
unsigned reg = 0;
|
||||
unsigned end = 0;
|
||||
bool allocateSpaceFound = false;
|
||||
if (res->IsUnbounded()) {
|
||||
if (alloc0.GetUnbounded() != nullptr) {
|
||||
const T *unbounded = alloc0.GetUnbounded();
|
||||
if (alloc.GetUnbounded() != nullptr) {
|
||||
const T *unbounded = alloc.GetUnbounded();
|
||||
Ctx.emitError(Twine("more than one unbounded resource (") +
|
||||
unbounded->GetGlobalName() + Twine(" and ") +
|
||||
res->GetGlobalName() + Twine(") in space ") +
|
||||
|
@ -191,26 +190,26 @@ private:
|
|||
continue;
|
||||
}
|
||||
|
||||
if (reservedAlloc0.FindForUnbounded(reg)) {
|
||||
if (reservedAlloc.FindForUnbounded(reg)) {
|
||||
end = UINT_MAX;
|
||||
allocateSpaceFound = true;
|
||||
}
|
||||
}
|
||||
else if (reservedAlloc0.Find(res->GetRangeSize(), reg)) {
|
||||
else if (reservedAlloc.Find(res->GetRangeSize(), reg)) {
|
||||
end = reg + res->GetRangeSize() - 1;
|
||||
allocateSpaceFound = true;
|
||||
}
|
||||
|
||||
if (allocateSpaceFound) {
|
||||
bool success = reservedAlloc0.Insert(res.get(), reg, end) == nullptr;
|
||||
bool success = reservedAlloc.Insert(res.get(), reg, end) == nullptr;
|
||||
DXASSERT_NOMSG(success);
|
||||
|
||||
success = alloc0.Insert(res.get(), reg, end) == nullptr;
|
||||
success = alloc.Insert(res.get(), reg, end) == nullptr;
|
||||
DXASSERT_NOMSG(success);
|
||||
|
||||
if (res->IsUnbounded()) {
|
||||
alloc0.SetUnbounded(res.get());
|
||||
reservedAlloc0.SetUnbounded(res.get());
|
||||
alloc.SetUnbounded(res.get());
|
||||
reservedAlloc.SetUnbounded(res.get());
|
||||
}
|
||||
|
||||
res->SetLowerBound(reg);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "dxc/DXIL/DxilConstants.h"
|
||||
#include "dxc/Support/WinAdapter.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
|
@ -201,6 +202,7 @@ private:
|
|||
public:
|
||||
UnusualAnnotation(UnusualAnnotationKind kind) : Kind(kind), Loc() { }
|
||||
UnusualAnnotation(UnusualAnnotationKind kind, clang::SourceLocation loc) : Kind(kind), Loc(loc) { }
|
||||
UnusualAnnotation(const UnusualAnnotation& other) : Kind(other.Kind), Loc(other.Loc) {}
|
||||
UnusualAnnotationKind getKind() const { return Kind; }
|
||||
|
||||
UnusualAnnotation* CopyToASTContext(clang::ASTContext& Context);
|
||||
|
@ -215,35 +217,22 @@ public:
|
|||
struct RegisterAssignment : public UnusualAnnotation
|
||||
{
|
||||
/// <summary>Initializes a new RegisterAssignment in invalid state.</summary>
|
||||
RegisterAssignment() : UnusualAnnotation(UA_RegisterAssignment),
|
||||
ShaderProfile(), IsValid(false),
|
||||
RegisterType(0), RegisterNumber(0), RegisterSpace(0), RegisterOffset(0)
|
||||
{
|
||||
}
|
||||
|
||||
RegisterAssignment(const RegisterAssignment& other) : UnusualAnnotation(UA_RegisterAssignment, other.Loc),
|
||||
ShaderProfile(other.ShaderProfile),
|
||||
IsValid(other.IsValid),
|
||||
RegisterType(other.RegisterType),
|
||||
RegisterNumber(other.RegisterNumber),
|
||||
RegisterSpace(other.RegisterSpace),
|
||||
RegisterOffset(other.RegisterOffset)
|
||||
{
|
||||
}
|
||||
RegisterAssignment() : UnusualAnnotation(UA_RegisterAssignment) { }
|
||||
|
||||
llvm::StringRef ShaderProfile;
|
||||
bool IsValid;
|
||||
char RegisterType; // 'x' means only space is assigned from the source code
|
||||
uint32_t RegisterNumber;
|
||||
uint32_t RegisterSpace;
|
||||
uint32_t RegisterOffset;
|
||||
bool IsValid = false;
|
||||
char RegisterType = 0; // Lower-case letter, 0 if not explicitly set
|
||||
uint32_t RegisterNumber = 0; // Iff RegisterType != 0
|
||||
llvm::Optional<uint32_t> RegisterSpace; // Set only if explicit "spaceN" syntax
|
||||
uint32_t RegisterOffset = 0;
|
||||
|
||||
void setIsValid(bool value) {
|
||||
IsValid = value;
|
||||
}
|
||||
|
||||
void setAsSpaceOnly() { RegisterType = 'x'; }
|
||||
bool isSpaceOnly() const { return RegisterType == 'x'; }
|
||||
bool isSpaceOnly() const {
|
||||
return RegisterType == 0 && RegisterSpace.hasValue();
|
||||
}
|
||||
|
||||
static bool classof(const UnusualAnnotation *UA) {
|
||||
return UA->getKind() == UA_RegisterAssignment;
|
||||
|
|
|
@ -1002,8 +1002,6 @@ def err_hlsl_unsupported_register_noninteger : Error<
|
|||
"register subcomponent is not an integral constant">;
|
||||
def err_hlsl_unsupported_register_type : Error<
|
||||
"register type is unsupported - available types are 'b', 'c', 'i', 's', 't', 'u'">;
|
||||
def err_hlsl_missing_register_type_and_number : Error<
|
||||
"missing register type and number">;
|
||||
def err_hlsl_unsupported_space_number : Error<
|
||||
"space number should be an integral numeric string">;
|
||||
def err_hlsl_modifier_after_type : Error<
|
||||
|
|
|
@ -7530,10 +7530,6 @@ def err_hlsl_unsupported_lvalue_cast_op : Error<
|
|||
"cannot truncate lvalue vector/matrix">;
|
||||
def err_hlsl_unsupported_buffer_packoffset : Error<
|
||||
"packoffset is only allowed within a constant buffer, not on the constant buffer declaration">;
|
||||
def err_hlsl_unsupported_cbuffer_register : Error<
|
||||
"invalid register specification, expected 'b' binding">;
|
||||
def err_hlsl_unsupported_tbuffer_register : Error<
|
||||
"invalid register specification, expected 't' binding">;
|
||||
def err_hlsl_unsupported_buffer_slot_target_specific : Error<
|
||||
"user defined constant buffer slots cannot be target specific">;
|
||||
def err_hlsl_unsupported_builtin_op: Error<
|
||||
|
|
|
@ -1021,13 +1021,19 @@ void ASTDumper::dumpHLSLUnusualAnnotations(const ArrayRef<hlsl::UnusualAnnotatio
|
|||
OS << " register(";
|
||||
if (!registerAssignment->ShaderProfile.empty())
|
||||
OS << registerAssignment->ShaderProfile << ", ";
|
||||
if (!registerAssignment->RegisterType)
|
||||
OS << "invalid";
|
||||
else
|
||||
OS << std::string(&(registerAssignment->RegisterType), 1);
|
||||
OS << registerAssignment->RegisterNumber + registerAssignment->RegisterOffset;
|
||||
if (registerAssignment->RegisterSpace)
|
||||
OS << ", space" << registerAssignment->RegisterSpace;
|
||||
bool needsComma = false;
|
||||
if (!registerAssignment->isSpaceOnly()) {
|
||||
if (!registerAssignment->RegisterType)
|
||||
OS << "invalid";
|
||||
else
|
||||
OS << StringRef(®isterAssignment->RegisterType, 1);
|
||||
OS << registerAssignment->RegisterNumber + registerAssignment->RegisterOffset;
|
||||
needsComma = true;
|
||||
}
|
||||
if (registerAssignment->RegisterSpace.hasValue()) {
|
||||
if (needsComma) OS << ", ";
|
||||
OS << "space" << registerAssignment->RegisterSpace.getValue();
|
||||
}
|
||||
OS << ")";
|
||||
if (!registerAssignment->IsValid)
|
||||
OS << " invalid";
|
||||
|
|
|
@ -2337,12 +2337,43 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
static void InitFromUnusualAnnotations(DxilResourceBase &Resource, NamedDecl &Decl) {
|
||||
for (hlsl::UnusualAnnotation* It : Decl.getUnusualAnnotations()) {
|
||||
switch (It->getKind()) {
|
||||
case hlsl::UnusualAnnotation::UA_RegisterAssignment: {
|
||||
hlsl::RegisterAssignment* RegAssign = cast<hlsl::RegisterAssignment>(It);
|
||||
if (RegAssign->RegisterType) {
|
||||
Resource.SetLowerBound(RegAssign->RegisterNumber);
|
||||
// For backcompat, don't auto-assign the register space if there's an
|
||||
// explicit register type.
|
||||
Resource.SetSpaceID(RegAssign->RegisterSpace.getValueOr(0));
|
||||
}
|
||||
else {
|
||||
Resource.SetSpaceID(RegAssign->RegisterSpace.getValueOr(UINT_MAX));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case hlsl::UnusualAnnotation::UA_SemanticDecl:
|
||||
// Ignore Semantics
|
||||
break;
|
||||
case hlsl::UnusualAnnotation::UA_ConstantPacking:
|
||||
// Should be handled by front-end
|
||||
llvm_unreachable("packoffset on resource");
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unknown UnusualAnnotation on resource");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t CGMSHLSLRuntime::AddSampler(VarDecl *samplerDecl) {
|
||||
llvm::GlobalVariable *val =
|
||||
cast<llvm::GlobalVariable>(CGM.GetAddrOfGlobalVar(samplerDecl));
|
||||
|
||||
unique_ptr<DxilSampler> hlslRes(new DxilSampler);
|
||||
hlslRes->SetLowerBound(UINT_MAX);
|
||||
hlslRes->SetSpaceID(UINT_MAX);
|
||||
hlslRes->SetGlobalSymbol(val);
|
||||
hlslRes->SetGlobalName(samplerDecl->getName());
|
||||
|
||||
|
@ -2356,27 +2387,7 @@ uint32_t CGMSHLSLRuntime::AddSampler(VarDecl *samplerDecl) {
|
|||
DxilSampler::SamplerKind kind = KeywordToSamplerKind(RT->getDecl()->getName());
|
||||
|
||||
hlslRes->SetSamplerKind(kind);
|
||||
|
||||
for (hlsl::UnusualAnnotation *it : samplerDecl->getUnusualAnnotations()) {
|
||||
switch (it->getKind()) {
|
||||
case hlsl::UnusualAnnotation::UA_RegisterAssignment: {
|
||||
hlsl::RegisterAssignment *ra = cast<hlsl::RegisterAssignment>(it);
|
||||
hlslRes->SetLowerBound(ra->RegisterNumber);
|
||||
hlslRes->SetSpaceID(ra->RegisterSpace);
|
||||
break;
|
||||
}
|
||||
case hlsl::UnusualAnnotation::UA_SemanticDecl:
|
||||
// Ignore Semantics
|
||||
break;
|
||||
case hlsl::UnusualAnnotation::UA_ConstantPacking:
|
||||
// Should be handled by front-end
|
||||
llvm_unreachable("packoffset on sampler");
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unknown UnusualAnnotation on sampler");
|
||||
break;
|
||||
}
|
||||
}
|
||||
InitFromUnusualAnnotations(*hlslRes, *samplerDecl);
|
||||
|
||||
hlslRes->SetID(m_pHLModule->GetSamplers().size());
|
||||
return m_pHLModule->AddSampler(std::move(hlslRes));
|
||||
|
@ -2732,6 +2743,7 @@ uint32_t CGMSHLSLRuntime::AddUAVSRV(VarDecl *decl,
|
|||
|
||||
unique_ptr<HLResource> hlslRes(new HLResource);
|
||||
hlslRes->SetLowerBound(UINT_MAX);
|
||||
hlslRes->SetSpaceID(UINT_MAX);
|
||||
hlslRes->SetGlobalSymbol(val);
|
||||
hlslRes->SetGlobalName(decl->getName());
|
||||
|
||||
|
@ -2740,27 +2752,7 @@ uint32_t CGMSHLSLRuntime::AddUAVSRV(VarDecl *decl,
|
|||
GetResourceDeclElemTypeAndRangeSize(CGM, *m_pHLModule, *decl,
|
||||
VarTy, rangeSize);
|
||||
hlslRes->SetRangeSize(rangeSize);
|
||||
|
||||
for (hlsl::UnusualAnnotation *it : decl->getUnusualAnnotations()) {
|
||||
switch (it->getKind()) {
|
||||
case hlsl::UnusualAnnotation::UA_RegisterAssignment: {
|
||||
hlsl::RegisterAssignment *ra = cast<hlsl::RegisterAssignment>(it);
|
||||
hlslRes->SetLowerBound(ra->RegisterNumber);
|
||||
hlslRes->SetSpaceID(ra->RegisterSpace);
|
||||
break;
|
||||
}
|
||||
case hlsl::UnusualAnnotation::UA_SemanticDecl:
|
||||
// Ignore Semantics
|
||||
break;
|
||||
case hlsl::UnusualAnnotation::UA_ConstantPacking:
|
||||
// Should be handled by front-end
|
||||
llvm_unreachable("packoffset on uav/srv");
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unknown UnusualAnnotation on uav/srv");
|
||||
break;
|
||||
}
|
||||
}
|
||||
InitFromUnusualAnnotations(*hlslRes, *decl);
|
||||
|
||||
if (decl->hasAttr<HLSLGloballyCoherentAttr>()) {
|
||||
hlslRes->SetGloballyCoherent(true);
|
||||
|
@ -2853,6 +2845,13 @@ void CGMSHLSLRuntime::AddConstant(VarDecl *constDecl, HLCBuffer &CB) {
|
|||
case hlsl::UnusualAnnotation::UA_RegisterAssignment: {
|
||||
if (isGlobalCB) {
|
||||
RegisterAssignment *ra = cast<RegisterAssignment>(it);
|
||||
if (ra->RegisterSpace.hasValue()) {
|
||||
DiagnosticsEngine& Diags = CGM.getDiags();
|
||||
unsigned DiagID = Diags.getCustomDiagID(
|
||||
DiagnosticsEngine::Error,
|
||||
"register space cannot be specified on global constants.");
|
||||
Diags.Report(it->Loc, DiagID);
|
||||
}
|
||||
offset = ra->RegisterNumber << 2;
|
||||
// Change to byte.
|
||||
offset <<= 2;
|
||||
|
@ -2868,6 +2867,7 @@ void CGMSHLSLRuntime::AddConstant(VarDecl *constDecl, HLCBuffer &CB) {
|
|||
|
||||
std::unique_ptr<DxilResourceBase> pHlslConst = llvm::make_unique<DxilResourceBase>(DXIL::ResourceClass::Invalid);
|
||||
pHlslConst->SetLowerBound(UINT_MAX);
|
||||
pHlslConst->SetSpaceID(0);
|
||||
pHlslConst->SetGlobalSymbol(cast<llvm::GlobalVariable>(constVal));
|
||||
pHlslConst->SetGlobalName(constDecl->getName());
|
||||
|
||||
|
@ -2913,6 +2913,7 @@ uint32_t CGMSHLSLRuntime::AddCBuffer(HLSLBufferDecl *D) {
|
|||
// setup the CB
|
||||
CB->SetGlobalSymbol(nullptr);
|
||||
CB->SetGlobalName(D->getNameAsString());
|
||||
CB->SetSpaceID(UINT_MAX);
|
||||
CB->SetLowerBound(UINT_MAX);
|
||||
if (!D->isCBuffer()) {
|
||||
CB->SetKind(DXIL::ResourceKind::TBuffer);
|
||||
|
@ -2921,24 +2922,7 @@ uint32_t CGMSHLSLRuntime::AddCBuffer(HLSLBufferDecl *D) {
|
|||
// the global variable will only used once by the createHandle?
|
||||
// SetHandle(llvm::Value *pHandle);
|
||||
|
||||
for (hlsl::UnusualAnnotation *it : D->getUnusualAnnotations()) {
|
||||
switch (it->getKind()) {
|
||||
case hlsl::UnusualAnnotation::UA_RegisterAssignment: {
|
||||
hlsl::RegisterAssignment *ra = cast<hlsl::RegisterAssignment>(it);
|
||||
uint32_t regNum = ra->RegisterNumber;
|
||||
uint32_t regSpace = ra->RegisterSpace;
|
||||
CB->SetSpaceID(regSpace);
|
||||
CB->SetLowerBound(regNum);
|
||||
break;
|
||||
}
|
||||
case hlsl::UnusualAnnotation::UA_SemanticDecl:
|
||||
// skip semantic on constant buffer
|
||||
break;
|
||||
case hlsl::UnusualAnnotation::UA_ConstantPacking:
|
||||
llvm_unreachable("no packoffset on constant buffer");
|
||||
break;
|
||||
}
|
||||
}
|
||||
InitFromUnusualAnnotations(*CB, *D);
|
||||
|
||||
// Add constant
|
||||
if (D->isConstantBufferView()) {
|
||||
|
|
|
@ -214,9 +214,12 @@ static void ParseRegisterNumberForHLSL(_In_z_ const char *name,
|
|||
DXASSERT_NOMSG(registerNumber != nullptr);
|
||||
DXASSERT_NOMSG(diagId != nullptr);
|
||||
|
||||
if (*name != 'b' && *name != 'c' && *name != 'i' && *name != 's' &&
|
||||
*name != 't' && *name != 'u' && *name != 'B' && *name != 'C' &&
|
||||
*name != 'I' && *name != 'S' && *name != 'T' && *name != 'U') {
|
||||
char firstLetter = name[0];
|
||||
if (firstLetter >= 'A' && firstLetter <= 'Z')
|
||||
firstLetter += 'a' - 'A';
|
||||
|
||||
StringRef validExplicitRegisterTypes("bcistu");
|
||||
if (validExplicitRegisterTypes.find(firstLetter) == StringRef::npos) {
|
||||
*diagId = diag::err_hlsl_unsupported_register_type;
|
||||
*registerType = 0;
|
||||
*registerNumber = 0;
|
||||
|
@ -226,7 +229,7 @@ static void ParseRegisterNumberForHLSL(_In_z_ const char *name,
|
|||
*registerType = *name;
|
||||
++name;
|
||||
|
||||
// It's valid to omit the register name.
|
||||
// It's valid to omit the register number.
|
||||
if (*name) {
|
||||
char *nameEnd;
|
||||
unsigned long num;
|
||||
|
@ -393,20 +396,11 @@ bool Parser::MaybeParseHLSLAttributes(std::vector<hlsl::UnusualAnnotation *> &ta
|
|||
DXASSERT(Tok.is(tok::identifier), "otherwise previous code should have failed");
|
||||
unsigned diagId;
|
||||
|
||||
// SPIRV Change Starts
|
||||
bool hasOnlySpace = false;
|
||||
identifierText = Tok.getIdentifierInfo()->getName().data();
|
||||
if (strncmp(identifierText, "space", strlen("space")) == 0) {
|
||||
if (!getLangOpts().SPIRV) {
|
||||
Diag(Tok.getLocation(),
|
||||
diag::err_hlsl_missing_register_type_and_number);
|
||||
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
|
||||
return true;
|
||||
}
|
||||
hasOnlySpace = true;
|
||||
} else {
|
||||
// SPIRV Change Ends
|
||||
|
||||
ParseRegisterNumberForHLSL(
|
||||
Tok.getIdentifierInfo()->getName().data(), &r.RegisterType, &r.RegisterNumber, &diagId);
|
||||
if (diagId == 0) {
|
||||
|
@ -461,22 +455,19 @@ bool Parser::MaybeParseHLSLAttributes(std::vector<hlsl::UnusualAnnotation *> &ta
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// SPIRV Change Starts
|
||||
}
|
||||
if (hasOnlySpace) {
|
||||
ParseSpaceForHLSL(Tok.getIdentifierInfo()->getName().data(), &r.RegisterSpace, &diagId);
|
||||
unsigned RegisterSpaceValue = 0;
|
||||
ParseSpaceForHLSL(Tok.getIdentifierInfo()->getName().data(), &RegisterSpaceValue, &diagId);
|
||||
if (diagId != 0) {
|
||||
Diag(Tok.getLocation(), diagId);
|
||||
r.setIsValid(false);
|
||||
} else {
|
||||
r.setAsSpaceOnly();
|
||||
r.RegisterSpace = RegisterSpaceValue;
|
||||
r.setIsValid(true);
|
||||
}
|
||||
ConsumeToken(); // consume identifier
|
||||
} else {
|
||||
// SPIRV Change Ends
|
||||
|
||||
if (Tok.is(tok::comma)) {
|
||||
ConsumeToken(); // consume comma
|
||||
if (!Tok.is(tok::identifier)) {
|
||||
|
@ -484,15 +475,18 @@ bool Parser::MaybeParseHLSLAttributes(std::vector<hlsl::UnusualAnnotation *> &ta
|
|||
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
|
||||
return true;
|
||||
}
|
||||
ParseSpaceForHLSL(Tok.getIdentifierInfo()->getName().data(), &r.RegisterSpace, &diagId);
|
||||
unsigned RegisterSpaceVal = 0;
|
||||
ParseSpaceForHLSL(Tok.getIdentifierInfo()->getName().data(), &RegisterSpaceVal, &diagId);
|
||||
if (diagId != 0) {
|
||||
Diag(Tok.getLocation(), diagId);
|
||||
r.setIsValid(false);
|
||||
}
|
||||
else {
|
||||
r.RegisterSpace = RegisterSpaceVal;
|
||||
}
|
||||
ConsumeToken(); // consume identifier
|
||||
}
|
||||
|
||||
} // SPIRV Change
|
||||
}
|
||||
|
||||
if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
|
||||
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
|
||||
|
|
|
@ -107,15 +107,13 @@ Decl *Parser::ParseConstBuffer(unsigned Context, SourceLocation &DeclEnd,
|
|||
ArrayRef<hlsl::UnusualAnnotation*> annotations = namedDecl->getUnusualAnnotations();
|
||||
for (hlsl::UnusualAnnotation* annotation : annotations) {
|
||||
if (const auto *regAssignment = dyn_cast<hlsl::RegisterAssignment>(annotation)) {
|
||||
// SPIRV Change Starts - skip the check if space-only for SPIR-V
|
||||
if (getLangOpts().SPIRV && regAssignment->isSpaceOnly())
|
||||
if (regAssignment->isSpaceOnly())
|
||||
continue;
|
||||
// SPIRV Change Ends
|
||||
if (isCBuffer && regAssignment->RegisterType != 'b' && regAssignment->RegisterType != 'B') {
|
||||
Diag(namedDecl->getLocation(), diag::err_hlsl_unsupported_cbuffer_register);
|
||||
Diag(namedDecl->getLocation(), diag::err_hlsl_incorrect_bind_semantic) << "'b'";
|
||||
}
|
||||
else if (!isCBuffer && regAssignment->RegisterType != 't' && regAssignment->RegisterType != 'T') {
|
||||
Diag(namedDecl->getLocation(), diag::err_hlsl_unsupported_tbuffer_register);
|
||||
Diag(namedDecl->getLocation(), diag::err_hlsl_incorrect_bind_semantic) << "'t'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1334,7 +1334,7 @@ public:
|
|||
bool getSetBinding(const hlsl::RegisterAssignment *regAttr, int *setNo,
|
||||
int *bindNo) const {
|
||||
std::ostringstream iss;
|
||||
iss << regAttr->RegisterSpace << regAttr->RegisterType
|
||||
iss << regAttr->RegisterSpace.getValueOr(0) << regAttr->RegisterType
|
||||
<< regAttr->RegisterNumber;
|
||||
|
||||
auto found = mapping.find(iss.str());
|
||||
|
@ -1450,7 +1450,7 @@ bool DeclResultIdMapper::decorateResourceBindings() {
|
|||
if (const auto *vkBinding = var.getBinding())
|
||||
set = vkBinding->getSet();
|
||||
else if (const auto *reg = var.getRegister())
|
||||
set = reg->RegisterSpace;
|
||||
set = reg->RegisterSpace.getValueOr(0);
|
||||
|
||||
tryToDecorate(var.getSpirvInstr(), set, vkCBinding->getBinding());
|
||||
}
|
||||
|
@ -1476,7 +1476,7 @@ bool DeclResultIdMapper::decorateResourceBindings() {
|
|||
if (reg->isSpaceOnly())
|
||||
continue;
|
||||
|
||||
const uint32_t set = reg->RegisterSpace;
|
||||
const uint32_t set = reg->RegisterSpace.getValueOr(0);
|
||||
uint32_t binding = reg->RegisterNumber;
|
||||
switch (reg->RegisterType) {
|
||||
case 'b':
|
||||
|
@ -1509,7 +1509,7 @@ bool DeclResultIdMapper::decorateResourceBindings() {
|
|||
if (const auto *vkBinding = var.getBinding())
|
||||
set = vkBinding->getSet();
|
||||
else if (const auto *reg = var.getRegister())
|
||||
set = reg->RegisterSpace;
|
||||
set = reg->RegisterSpace.getValueOr(0);
|
||||
|
||||
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), set,
|
||||
bindingSet.useNextBinding(set));
|
||||
|
@ -1517,7 +1517,7 @@ bool DeclResultIdMapper::decorateResourceBindings() {
|
|||
} else if (!var.getBinding()) {
|
||||
const auto *reg = var.getRegister();
|
||||
if (reg && reg->isSpaceOnly()) {
|
||||
const uint32_t set = reg->RegisterSpace;
|
||||
const uint32_t set = reg->RegisterSpace.getValueOr(0);
|
||||
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), set,
|
||||
bindingSet.useNextBinding(set));
|
||||
} else if (!reg) {
|
||||
|
|
|
@ -9501,10 +9501,12 @@ void hlsl::DiagnoseRegisterType(
|
|||
clang::QualType type,
|
||||
char registerType)
|
||||
{
|
||||
// SPIRV Change Starts - skip the check if space-only for SPIR-V
|
||||
if (self->getLangOpts().SPIRV && registerType == 'x')
|
||||
// Register type can be zero if only a register space was provided.
|
||||
if (registerType == 0)
|
||||
return;
|
||||
// SPIRV Change Ends
|
||||
|
||||
if (registerType >= 'A' && registerType <= 'Z')
|
||||
registerType = registerType + ('a' - 'A');
|
||||
|
||||
HLSLExternalSource* source = HLSLExternalSource::FromSema(self);
|
||||
ArBasicKind element = source->GetTypeElementKind(type);
|
||||
|
@ -9535,8 +9537,7 @@ void hlsl::DiagnoseRegisterType(
|
|||
case AR_BASIC_MIN16INT:
|
||||
case AR_BASIC_MIN16UINT:
|
||||
expected = "'b', 'c', or 'i'";
|
||||
isValid = registerType == 'b' || registerType == 'c' || registerType == 'i' ||
|
||||
registerType == 'B' || registerType == 'C' || registerType == 'I';
|
||||
isValid = registerType == 'b' || registerType == 'c' || registerType == 'i';
|
||||
break;
|
||||
|
||||
case AR_OBJECT_TEXTURE1D:
|
||||
|
@ -9549,8 +9550,7 @@ void hlsl::DiagnoseRegisterType(
|
|||
case AR_OBJECT_TEXTURE2DMS:
|
||||
case AR_OBJECT_TEXTURE2DMS_ARRAY:
|
||||
expected = "'t' or 's'";
|
||||
isValid = registerType == 't' || registerType == 's' ||
|
||||
registerType == 'T' || registerType == 'S';
|
||||
isValid = registerType == 't' || registerType == 's';
|
||||
break;
|
||||
|
||||
case AR_OBJECT_SAMPLER:
|
||||
|
@ -9560,13 +9560,12 @@ void hlsl::DiagnoseRegisterType(
|
|||
case AR_OBJECT_SAMPLERCUBE:
|
||||
case AR_OBJECT_SAMPLERCOMPARISON:
|
||||
expected = "'s' or 't'";
|
||||
isValid = registerType == 's' || registerType == 't' ||
|
||||
registerType == 'S' || registerType == 'T';
|
||||
isValid = registerType == 's' || registerType == 't';
|
||||
break;
|
||||
|
||||
case AR_OBJECT_BUFFER:
|
||||
expected = "'t'";
|
||||
isValid = registerType == 't' || registerType == 'T';
|
||||
isValid = registerType == 't';
|
||||
break;
|
||||
|
||||
case AR_OBJECT_POINTSTREAM:
|
||||
|
@ -9589,13 +9588,13 @@ void hlsl::DiagnoseRegisterType(
|
|||
case AR_OBJECT_RWTEXTURE3D:
|
||||
case AR_OBJECT_RWBUFFER:
|
||||
expected = "'u'";
|
||||
isValid = registerType == 'u' || registerType == 'U';
|
||||
isValid = registerType == 'u';
|
||||
break;
|
||||
|
||||
case AR_OBJECT_BYTEADDRESS_BUFFER:
|
||||
case AR_OBJECT_STRUCTURED_BUFFER:
|
||||
expected = "'t'";
|
||||
isValid = registerType == 't' || registerType == 'T';
|
||||
isValid = registerType == 't';
|
||||
break;
|
||||
|
||||
case AR_OBJECT_CONSUME_STRUCTURED_BUFFER:
|
||||
|
@ -9605,16 +9604,16 @@ void hlsl::DiagnoseRegisterType(
|
|||
case AR_OBJECT_RWSTRUCTURED_BUFFER_CONSUME:
|
||||
case AR_OBJECT_APPEND_STRUCTURED_BUFFER:
|
||||
expected = "'u'";
|
||||
isValid = registerType == 'u' || registerType == 'U';
|
||||
isValid = registerType == 'u';
|
||||
break;
|
||||
|
||||
case AR_OBJECT_CONSTANT_BUFFER:
|
||||
expected = "'b'";
|
||||
isValid = registerType == 'b' || registerType == 'B';
|
||||
isValid = registerType == 'b';
|
||||
break;
|
||||
case AR_OBJECT_TEXTURE_BUFFER:
|
||||
expected = "'t'";
|
||||
isValid = registerType == 't' || registerType == 'T';
|
||||
isValid = registerType == 't';
|
||||
break;
|
||||
|
||||
case AR_OBJECT_ROVBUFFER:
|
||||
|
@ -9626,7 +9625,7 @@ void hlsl::DiagnoseRegisterType(
|
|||
case AR_OBJECT_ROVTEXTURE2D_ARRAY:
|
||||
case AR_OBJECT_ROVTEXTURE3D:
|
||||
expected = "'u'";
|
||||
isValid = registerType == 'u' || registerType == 'U';
|
||||
isValid = registerType == 'u';
|
||||
break;
|
||||
|
||||
case AR_OBJECT_LEGACY_EFFECT: // Used for all unsupported but ignored legacy effect types
|
||||
|
@ -9638,12 +9637,9 @@ void hlsl::DiagnoseRegisterType(
|
|||
|
||||
// fxc is inconsistent as to when it reports an error and when it ignores invalid bind semantics, so emit
|
||||
// a warning instead.
|
||||
if (!isValid)
|
||||
{
|
||||
if (isWarning)
|
||||
self->Diag(loc, diag::warn_hlsl_incorrect_bind_semantic) << expected;
|
||||
else
|
||||
self->Diag(loc, diag::err_hlsl_incorrect_bind_semantic) << expected;
|
||||
if (!isValid) {
|
||||
unsigned DiagID = isWarning ? diag::warn_hlsl_incorrect_bind_semantic : diag::err_hlsl_incorrect_bind_semantic;
|
||||
self->Diag(loc, DiagID) << expected;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11175,14 +11171,11 @@ Decl* Sema::ActOnStartHLSLBuffer(
|
|||
case hlsl::UnusualAnnotation::UA_RegisterAssignment: {
|
||||
hlsl::RegisterAssignment* registerAssignment = cast<hlsl::RegisterAssignment>(*unusualIter);
|
||||
|
||||
// SPIRV Change Starts - skip the check if space-only for SPIR-V
|
||||
if (getLangOpts().SPIRV && registerAssignment->isSpaceOnly())
|
||||
if (registerAssignment->isSpaceOnly())
|
||||
continue;
|
||||
// SPIRV Change Ends
|
||||
|
||||
if (registerAssignment->RegisterType != expectedRegisterType && registerAssignment->RegisterType != toupper(expectedRegisterType)) {
|
||||
Diag(registerAssignment->Loc, cbuffer ? diag::err_hlsl_unsupported_cbuffer_register :
|
||||
diag::err_hlsl_unsupported_tbuffer_register);
|
||||
Diag(registerAssignment->Loc, diag::err_hlsl_incorrect_bind_semantic) << (cbuffer ? "'b'" : "'t'");
|
||||
} else if (registerAssignment->ShaderProfile.size() > 0) {
|
||||
Diag(registerAssignment->Loc, diag::err_hlsl_unsupported_buffer_slot_target_specific);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: %dxc -E main -T vs_6_0 -auto-binding-space 1 %s | FileCheck %s
|
||||
|
||||
// Test that auto-binding-space affects only resources with no
|
||||
// explicit register nor space binding.
|
||||
|
||||
// CHECK: buf_a texture f32 buf T0 t0,space1 1
|
||||
// CHECK: buf_b texture f32 buf T1 t1 1
|
||||
// CHECK: buf_c texture f32 buf T2 t0,space2 1
|
||||
// CHECK: buf_d texture f32 buf T3 t2,space3 1
|
||||
Buffer buf_a;
|
||||
Buffer buf_b : register(t1);
|
||||
Buffer buf_c : register(space2);
|
||||
Buffer buf_d : register(t2,space3);
|
||||
|
||||
float main() : OUT {
|
||||
return buf_a[0] + buf_b[0] + buf_c[0] + buf_d[0];
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: %dxc -T lib_6_3 %s | FileCheck %s
|
||||
|
||||
// Test that auto-binding-space affects only resources with no
|
||||
// explicit register nor space binding.
|
||||
|
||||
// CHECK: buf_a texture f32 buf T0t4294967295,space4294967295 1
|
||||
// CHECK: buf_b texture f32 buf T1 t1 1
|
||||
// CHECK: buf_c texture f32 buf T2t4294967295,space2 1
|
||||
// CHECK: buf_d texture f32 buf T3 t2,space3 1
|
||||
Buffer buf_a;
|
||||
Buffer buf_b : register(t1);
|
||||
Buffer buf_c : register(space2);
|
||||
Buffer buf_d : register(t2,space3);
|
||||
|
||||
export float foo() {
|
||||
return buf_a[0] + buf_b[0] + buf_c[0] + buf_d[0];
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// RUN: %dxc -E main -T vs_6_0 %s | FileCheck %s
|
||||
|
||||
// Test resource allocation with space-only register annotations.
|
||||
|
||||
// CHECK-DAG: buf_s0_a texture f32 buf T0 t0 1
|
||||
// CHECK-DAG: buf_s1_a texture f32 buf T1 t0,space1 1
|
||||
// CHECK-DAG: buf_s0_b texture f32 buf T2 t1 1
|
||||
// CHECK-DAG: buf_s1_b texture f32 buf T3 t1,space1 1
|
||||
Buffer buf_s0_a;
|
||||
Buffer buf_s1_a : register(space1);
|
||||
Buffer buf_s0_b;
|
||||
Buffer buf_s1_b : register(space1);
|
||||
|
||||
float main() : OUT {
|
||||
return buf_s0_a[0] + buf_s1_a[0] + buf_s0_b[0] + buf_s1_b[0];
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
|
||||
|
||||
struct S { float val; };
|
||||
|
||||
// Constant buffers, space cb
|
||||
// CHECK-DAG: ; cb cbuffer NA NA CB0 cb0,space1 1
|
||||
// CHECK-DAG: ; cb2 cbuffer NA NA CB1 cb1,space1 1
|
||||
cbuffer cb : register(space1) { float cb_val; }
|
||||
ConstantBuffer<S> cb2 : register(space1);
|
||||
|
||||
// Samplers, space s
|
||||
// CHECK-DAG: ; s sampler NA NA S0 s0,space2 1
|
||||
SamplerState s : register(space2);
|
||||
|
||||
// SRVs, space t
|
||||
// CHECK-DAG: ; buf texture f32 buf T0 t0,space3 1
|
||||
// CHECK-DAG: ; tex texture f32 1d T1 t1,space3 1
|
||||
// CHECK-DAG: ; sbuf texture struct r/o T2 t2,space3 1
|
||||
// CHECK-DAG: ; babuf texture byte r/o T3 t3,space3 1
|
||||
// CHECK-DAG: ; tb texture u32 tbuffer T4 t4,space3 1
|
||||
// CHECK-DAG: ; tb2 texture u32 tbuffer T5 t5,space3 1
|
||||
Buffer<float> buf : register(space3);
|
||||
Texture1D<float> tex : register(space3);
|
||||
StructuredBuffer<float> sbuf : register(space3);
|
||||
ByteAddressBuffer babuf : register(space3);
|
||||
tbuffer tb : register(space3) { float tb_val; }
|
||||
TextureBuffer<S> tb2 : register(space3);
|
||||
|
||||
// UAVs, space u
|
||||
// CHECK-DAG: ; rwsbuf UAV struct r/w U0 u0,space4 1
|
||||
// CHECK-DAG: ; appbuf UAV struct r/w+cnt U1 u1,space4 1
|
||||
// CHECK-DAG: ; conbuf UAV struct r/w+cnt U2 u2,space4 1
|
||||
// CHECK-DAG: ; rwbabuf UAV byte r/w U3 u3,space4 1
|
||||
RWStructuredBuffer<float> rwsbuf : register(space4);
|
||||
AppendStructuredBuffer<float> appbuf : register(space4);
|
||||
ConsumeStructuredBuffer<float> conbuf : register(space4);
|
||||
RWByteAddressBuffer rwbabuf : register(space4);
|
||||
|
||||
// Use all resources so they get allocated
|
||||
float main() : SV_Target {
|
||||
appbuf.Append(0);
|
||||
return cb_val + cb2.val
|
||||
+ buf[0] + tex[0] + sbuf[0] + babuf.Load<float>(0) + tb_val + tb2.val
|
||||
+ rwsbuf[0] + conbuf.Consume() + rwbabuf.Load<float>(0)
|
||||
+ tex.Sample(s, 0);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// RUN: %dxc -E main -T vs_6_0 %s | FileCheck %s
|
||||
|
||||
// Test space-only register annotations with shader type specifier.
|
||||
|
||||
// CHECK: buf texture u32 buf T0 t0,space2 1
|
||||
Buffer<uint> buf : register(ps, space1) : register(vs, space2);
|
||||
|
||||
uint main() : OUT { return buf[0]; }
|
|
@ -0,0 +1,11 @@
|
|||
// RUN: %dxc -T vs_6_0 -E main %s | FileCheck %s
|
||||
|
||||
// Test that register annotations on globals constants affect the offset.
|
||||
|
||||
// CHECK: ; int x; ; Offset: 16
|
||||
// CHECK: ; int y; ; Offset: 0
|
||||
|
||||
int x : register(c1);
|
||||
int y : register(c0);
|
||||
|
||||
int2 main() : OUT { return int2(x, y); }
|
|
@ -1,36 +0,0 @@
|
|||
// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
|
||||
|
||||
// CHECK: :4:40: error: missing register type and number
|
||||
Buffer<float4> MyBuffer : register(space1);
|
||||
// CHECK: :6:40: error: missing register type and number
|
||||
Texture2D<float4> MyTexture : register(space1);
|
||||
|
||||
// CHECK: :9:30: error: missing register type and number
|
||||
cbuffer MyCbuffer : register(space2) {
|
||||
float4 CB_a;
|
||||
}
|
||||
|
||||
// CHECK: :14:30: error: missing register type and number
|
||||
tbuffer MyTbuffer : register(space2) {
|
||||
float4 TB_a;
|
||||
}
|
||||
|
||||
struct S { float4 val; };
|
||||
|
||||
// CHECK: :21:41: error: missing register type and number
|
||||
ConstantBuffer<S> MyCbuffer2 : register(space3);
|
||||
// CHECK: :23:41: error: missing register type and number
|
||||
TextureBuffer<S> MyTbuffer2 : register(space3);
|
||||
|
||||
// CHECK: :26:50: error: missing register type and number
|
||||
StructuredBuffer<S> MySbuffer1 : register(space4);
|
||||
// CHECK: :28:50: error: missing register type and number
|
||||
RWStructuredBuffer<S> MySbuffer2 : register(space4);
|
||||
// CHECK: :30:50: error: missing register type and number
|
||||
AppendStructuredBuffer<S> MySbuffer3 : register(space4);
|
||||
// CHECK: :32:50: error: missing register type and number
|
||||
ConsumeStructuredBuffer<S> MySbuffer4 : register(space4);
|
||||
|
||||
float4 main() : SV_Target {
|
||||
return MyBuffer[0];
|
||||
}
|
|
@ -1031,7 +1031,7 @@ static void Ref1_CheckBinding_b_buf(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
|
|||
VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_UAV_RWBYTEADDRESS);
|
||||
// not explicitly bound:
|
||||
VERIFY_ARE_EQUAL(resDesc.BindPoint, 4294967295);
|
||||
VERIFY_ARE_EQUAL(resDesc.Space, 0);
|
||||
VERIFY_ARE_EQUAL(resDesc.Space, 4294967295);
|
||||
VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -256,8 +256,6 @@ public:
|
|||
TEST_METHOD(WhenMissingPayloadThenFail)
|
||||
TEST_METHOD(ShaderFunctionReturnTypeVoid)
|
||||
|
||||
TEST_METHOD(SpaceOnlyRegisterFail)
|
||||
|
||||
TEST_METHOD(WhenDisassembleInvalidBlobThenFail)
|
||||
|
||||
dxc::DxcDllSupport m_dllSupport;
|
||||
|
@ -3055,10 +3053,6 @@ float4 main(uint vid : SV_ViewID, float3 In[31] : INPUT) : SV_Target \
|
|||
/*bRegex*/true);
|
||||
}
|
||||
|
||||
TEST_F(ValidationTest, SpaceOnlyRegisterFail) {
|
||||
TestCheck(L"..\\CodeGenHLSL\\space-only-register.hlsl");
|
||||
}
|
||||
|
||||
// Regression test for a double-delete when failing to parse bitcode.
|
||||
TEST_F(ValidationTest, WhenDisassembleInvalidBlobThenFail) {
|
||||
if (!m_dllSupport.IsEnabled()) {
|
||||
|
@ -3075,7 +3069,6 @@ TEST_F(ValidationTest, WhenDisassembleInvalidBlobThenFail) {
|
|||
VERIFY_FAILED(pCompiler->Disassemble(pInvalidBitcode, &pDisassembly));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(ValidationTest, GSMainMissingAttributeFail) {
|
||||
TestCheck(L"..\\CodeGenHLSL\\attributes-gs-no-inout-main.hlsl");
|
||||
}
|
||||
|
@ -3194,8 +3187,8 @@ TEST_F(ValidationTest, ResCounter) {
|
|||
RewriteAssemblyCheckMsg(
|
||||
"RWStructuredBuffer<float4> buf; export float GetCounter() {return buf.IncrementCounter();}",
|
||||
"lib_6_3",
|
||||
{ "!\"buf\", i32 0, i32 -1, i32 1, i32 12, i1 false, i1 true, i1 false, !" },
|
||||
{ "!\"buf\", i32 0, i32 -1, i32 1, i32 12, i1 false, i1 false, i1 false, !" },
|
||||
{ "!\"buf\", i32 -1, i32 -1, i32 1, i32 12, i1 false, i1 true, i1 false, !" },
|
||||
{ "!\"buf\", i32 -1, i32 -1, i32 1, i32 12, i1 false, i1 false, i1 false, !" },
|
||||
"BufferUpdateCounter valid only when HasCounter is true",
|
||||
true);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче