2
0
Эх сурвалжийг харах

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.
Tristan Labelle 6 жил өмнө
parent
commit
17624a864b
24 өөрчлөгдсөн 242 нэмэгдсэн , 213 устгасан
  1. 12 13
      lib/HLSL/DxilCondenseResources.cpp
  2. 11 22
      tools/clang/include/clang/AST/HlslTypes.h
  3. 0 2
      tools/clang/include/clang/Basic/DiagnosticParseKinds.td
  4. 0 4
      tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
  5. 13 7
      tools/clang/lib/AST/ASTDumper.cpp
  6. 44 60
      tools/clang/lib/CodeGen/CGHLSLMS.cpp
  7. 16 22
      tools/clang/lib/Parse/ParseDecl.cpp
  8. 3 5
      tools/clang/lib/Parse/ParseHLSL.cpp
  9. 5 5
      tools/clang/lib/SPIRV/DeclResultIdMapper.cpp
  10. 20 27
      tools/clang/lib/Sema/SemaHLSL.cpp
  11. 17 0
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/auto_binding_space.hlsl
  12. 0 0
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/legacy_reservation_arrays_sm50.hlsl
  13. 0 0
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/legacy_reservation_arrays_sm51.hlsl
  14. 0 0
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/legacy_reservation_sm50.hlsl
  15. 0 0
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/legacy_reservation_sm51.hlsl
  16. 0 0
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/legacy_reservation_unbounded.hlsl
  17. 17 0
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/register_args_lib.hlsl
  18. 16 0
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/space_only_alloc.hlsl
  19. 46 0
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/space_only_resource_types.hlsl
  20. 8 0
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/space_only_shader_type.hlsl
  21. 11 0
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/constant_buffers/globals_buffer_register_annotation.hlsl
  22. 0 36
      tools/clang/test/CodeGenHLSL/space-only-register.hlsl
  23. 1 1
      tools/clang/unittests/HLSL/DxilContainerTest.cpp
  24. 2 9
      tools/clang/unittests/HLSL/ValidationTest.cpp

+ 12 - 13
lib/HLSL/DxilCondenseResources.cpp

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

+ 11 - 22
tools/clang/include/clang/AST/HlslTypes.h

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

+ 0 - 2
tools/clang/include/clang/Basic/DiagnosticParseKinds.td

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

+ 0 - 4
tools/clang/include/clang/Basic/DiagnosticSemaKinds.td

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

+ 13 - 7
tools/clang/lib/AST/ASTDumper.cpp

@@ -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(&registerAssignment->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";

+ 44 - 60
tools/clang/lib/CodeGen/CGHLSLMS.cpp

@@ -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()) {

+ 16 - 22
tools/clang/lib/Parse/ParseDecl.cpp

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

+ 3 - 5
tools/clang/lib/Parse/ParseHLSL.cpp

@@ -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'";
       }
     }
   }

+ 5 - 5
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

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

+ 20 - 27
tools/clang/lib/Sema/SemaHLSL.cpp

@@ -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);
       }

+ 17 - 0
tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/auto_binding_space.hlsl

@@ -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
tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/resource_binding_fxccompat_arrays_sm50.hlsl → tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/legacy_reservation_arrays_sm50.hlsl


+ 0 - 0
tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/resource_binding_fxccompat_arrays_sm51.hlsl → tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/legacy_reservation_arrays_sm51.hlsl


+ 0 - 0
tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/resource_binding_fxccompat_sm50.hlsl → tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/legacy_reservation_sm50.hlsl


+ 0 - 0
tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/resource_binding_fxccompat_sm51.hlsl → tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/legacy_reservation_sm51.hlsl


+ 0 - 0
tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/resource_binding_fxccompat_sm50_no_unbounded.hlsl → tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/legacy_reservation_unbounded.hlsl


+ 17 - 0
tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/register_args_lib.hlsl

@@ -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];
+}

+ 16 - 0
tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/space_only_alloc.hlsl

@@ -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];
+}

+ 46 - 0
tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/space_only_resource_types.hlsl

@@ -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);
+}

+ 8 - 0
tools/clang/test/CodeGenHLSL/batch/declarations/resources/binding/space_only_shader_type.hlsl

@@ -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]; }

+ 11 - 0
tools/clang/test/CodeGenHLSL/batch/declarations/resources/constant_buffers/globals_buffer_register_annotation.hlsl

@@ -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); }

+ 0 - 36
tools/clang/test/CodeGenHLSL/space-only-register.hlsl

@@ -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];
-}

+ 1 - 1
tools/clang/unittests/HLSL/DxilContainerTest.cpp

@@ -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);
 }
 

+ 2 - 9
tools/clang/unittests/HLSL/ValidationTest.cpp

@@ -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);
 }