Browse Source

[spirv] Add CL option for stage I/O location assignment order (#578)

A new CL option -fvk-stage-io-order={alpha|decl} is added to
control the order for assigning stage I/O location numbers.
The default is also changed to declaration order (decl) instead
of alphabetical order (alpha).

Also extended testing fixtures to support additional CL options.
Lei Zhang 8 years ago
parent
commit
0e0e014232

+ 5 - 6
docs/SPIR-V.rst

@@ -232,9 +232,6 @@ HLSL variables and resources
 
 
 This section lists how various HLSL variables and resources are mapped.
 This section lists how various HLSL variables and resources are mapped.
 
 
-Variable definition
-+++++++++++++++++++
-
 Variables are defined in HLSL using the following
 Variables are defined in HLSL using the following
 `syntax <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509706(v=vs.85).aspx>`_
 `syntax <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509706(v=vs.85).aspx>`_
 rules::
 rules::
@@ -331,7 +328,7 @@ to ``Location`` 1.
 
 
 [TODO] Another explicit way: using command-line options
 [TODO] Another explicit way: using command-line options
 
 
-Please note that the compiler does prohibits mixing the explicit and implicit
+Please note that the compiler prohibits mixing the explicit and implicit
 approach for the same SigPoint to avoid complexity and fallibility. However,
 approach for the same SigPoint to avoid complexity and fallibility. However,
 for a certain shader stage, one SigPoint using the explicit approach while the
 for a certain shader stage, one SigPoint using the explicit approach while the
 other adopting the implicit approach is permitted.
 other adopting the implicit approach is permitted.
@@ -375,8 +372,10 @@ corresponding SPIR-V ``Builtin``  decorations according to the above table.
 SV semantic strings not translated into SPIR-V BuiltIn decorations will be
 SV semantic strings not translated into SPIR-V BuiltIn decorations will be
 handled similarly as non-SV (arbitrary) semantic strings: a SPIR-V variable
 handled similarly as non-SV (arbitrary) semantic strings: a SPIR-V variable
 of the ``Input``/``Output`` storage class will be created for each entity with
 of the ``Input``/``Output`` storage class will be created for each entity with
-such semantic string. Then sort all semantic strings alphabetically, and assign
-``Location`` numbers sequentially to each SPIR-V variable. Note that this means
+such semantic string. Then sort all semantic strings according to declaration
+(the default, or if ``-fvk-stage-io-order=decl`` is given) or alphabetical
+(if ``-fvk-stage-io-order=alpha`` is given) order, and assign ``Location``
+numbers sequentially to the corresponding SPIR-V variables. Note that this means
 flattening all structs if structs are used as function parameters or returns.
 flattening all structs if structs are used as function parameters or returns.
 
 
 There is an exception to the above rule for SV_Target[N]. It will always be
 There is an exception to the above rule for SV_Target[N]. It will always be

+ 7 - 1
include/dxc/Support/HLSLOptions.h

@@ -112,7 +112,6 @@ public:
 
 
   bool AllResourcesBound; // OPT_all_resources_bound
   bool AllResourcesBound; // OPT_all_resources_bound
   bool AstDump; // OPT_ast_dump
   bool AstDump; // OPT_ast_dump
-  bool GenSPIRV; // OPT_spirv // SPIRV change
   bool ColorCodeAssembly; // OPT_Cc
   bool ColorCodeAssembly; // OPT_Cc
   bool CodeGenHighLevel; // OPT_fcgl
   bool CodeGenHighLevel; // OPT_fcgl
   bool DebugInfo; // OPT__SLASH_Zi
   bool DebugInfo; // OPT__SLASH_Zi
@@ -157,6 +156,13 @@ public:
   bool DisaseembleHex; //OPT_Lx
   bool DisaseembleHex; //OPT_Lx
   bool IsRootSignatureProfile();
   bool IsRootSignatureProfile();
   bool IsLibraryProfile();
   bool IsLibraryProfile();
+
+  // SPIRV Change Starts
+#ifdef ENABLE_SPIRV_CODEGEN
+  bool GenSPIRV; // OPT_spirv
+  llvm::StringRef VkStageIoOrder;
+#endif
+  // SPIRV Change Ends
 };
 };
 
 
 /// Use this class to capture, convert and handle the lifetime for the
 /// Use this class to capture, convert and handle the lifetime for the

+ 9 - 2
include/dxc/Support/HLSLOptions.td

@@ -67,6 +67,8 @@ def hlsloptz_Group : OptionGroup<"HLSL Optimization">, HelpText<"Optimization Op
 def hlslutil_Group : OptionGroup<"HLSL Utility">, HelpText<"Utility Options">;
 def hlslutil_Group : OptionGroup<"HLSL Utility">, HelpText<"Utility Options">;
 def hlslcore_Group : OptionGroup<"HLSL Core">, HelpText<"Common Options">;
 def hlslcore_Group : OptionGroup<"HLSL Core">, HelpText<"Common Options">;
 
 
+def spirv_Group : OptionGroup<"SPIR-V CodeGen">, HelpText<"SPIR-V CodeGen Options">; // SPIRV Change
+
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 // Options
 // Options
 
 
@@ -209,8 +211,6 @@ def _help_question : Flag<["-", "/"], "?">, Flags<[DriverOption]>, Alias<help>;
 
 
 def ast_dump : Flag<["-", "/"], "ast-dump">, Flags<[CoreOption, DriverOption, HelpHidden]>,
 def ast_dump : Flag<["-", "/"], "ast-dump">, Flags<[CoreOption, DriverOption, HelpHidden]>,
   HelpText<"Dumps the parsed Abstract Syntax Tree.">; // should not be core, but handy workaround until explicit API written
   HelpText<"Dumps the parsed Abstract Syntax Tree.">; // should not be core, but handy workaround until explicit API written
-def spirv : Flag<["-"], "spirv">, Flags<[CoreOption, DriverOption, HelpHidden]>, // SPIRV change: temporary solution to support
-  HelpText<"Generates SPIR-V binary code">;                                      // SPIRV change: SPIR-V gen in a command line tool
 def external_lib : Separate<["-", "/"], "external">, Group<hlslcore_Group>, Flags<[DriverOption, HelpHidden]>,
 def external_lib : Separate<["-", "/"], "external">, Group<hlslcore_Group>, Flags<[DriverOption, HelpHidden]>,
   HelpText<"External DLL name to load for compiler support">;
   HelpText<"External DLL name to load for compiler support">;
 def external_fn : Separate<["-", "/"], "external-fn">, Group<hlslcore_Group>, Flags<[DriverOption, HelpHidden]>,
 def external_fn : Separate<["-", "/"], "external-fn">, Group<hlslcore_Group>, Flags<[DriverOption, HelpHidden]>,
@@ -233,6 +233,13 @@ def no_min_precision: Flag<["-", "/"], "no-min-precision">, Flags<[CoreOption, D
   HelpText<"Do not use min precision but use strict precision types.">;
   HelpText<"Do not use min precision but use strict precision types.">;
 def ignore_line_directives : Flag<["-", "/"], "ignore-line-directives">, HelpText<"Ignore line directives">, Flags<[CoreOption]>, Group<hlslcomp_Group>;
 def ignore_line_directives : Flag<["-", "/"], "ignore-line-directives">, HelpText<"Ignore line directives">, Flags<[CoreOption]>, Group<hlslcomp_Group>;
 
 
+// SPIRV Change Starts
+def spirv : Flag<["-"], "spirv">, Group<spirv_Group>, Flags<[CoreOption, DriverOption, HelpHidden]>,
+  HelpText<"Generate SPIR-V binary code">;
+def fvk_stage_io_order_EQ : Joined<["-"], "fvk-stage-io-order=">, Group<spirv_Group>, Flags<[CoreOption, DriverOption, HelpHidden]>,
+  HelpText<"Specify Vulkan stage I/O location assignment order">;
+// SPIRV Change Ends
+
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 // fxc-based flags that don't match those previously defined.
 // fxc-based flags that don't match those previously defined.
 
 

+ 19 - 1
lib/DxcSupport/HLSLOptions.cpp

@@ -278,7 +278,6 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   opts.UseHexLiterals = Args.hasFlag(OPT_Lx, OPT_INVALID);
   opts.UseHexLiterals = Args.hasFlag(OPT_Lx, OPT_INVALID);
   opts.Preprocess = Args.getLastArgValue(OPT_P);
   opts.Preprocess = Args.getLastArgValue(OPT_P);
   opts.AstDump = Args.hasFlag(OPT_ast_dump, OPT_INVALID, false);
   opts.AstDump = Args.hasFlag(OPT_ast_dump, OPT_INVALID, false);
-  opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false); // SPIRV change
   opts.CodeGenHighLevel = Args.hasFlag(OPT_fcgl, OPT_INVALID, false);
   opts.CodeGenHighLevel = Args.hasFlag(OPT_fcgl, OPT_INVALID, false);
   opts.DebugInfo = Args.hasFlag(OPT__SLASH_Zi, OPT_INVALID, false);
   opts.DebugInfo = Args.hasFlag(OPT__SLASH_Zi, OPT_INVALID, false);
   opts.DebugNameForBinary = Args.hasFlag(OPT_Zsb, OPT_INVALID, false);
   opts.DebugNameForBinary = Args.hasFlag(OPT_Zsb, OPT_INVALID, false);
@@ -432,6 +431,25 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
     return 1;
     return 1;
   }
   }
 
 
+  // SPIRV Change Starts
+#ifdef ENABLE_SPIRV_CODEGEN
+  opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
+  opts.VkStageIoOrder = Args.getLastArgValue(OPT_fvk_stage_io_order_EQ, "decl");
+  if (opts.VkStageIoOrder != "alpha" && opts.VkStageIoOrder != "decl") {
+    errors << "Unknown Vulkan stage I/O location assignment order : "
+           << opts.VkStageIoOrder;
+    return 1;
+  }
+#else
+  if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) ||
+      !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty()) {
+    errors << "SPIR-V CodeGen not available. "
+              "Please recompile with -DENABLE_SPIRV_CODEGEN=ON.";
+    return 1;
+  }
+#endif
+  // SPIRV Change Ends
+
   opts.Args = std::move(Args);
   opts.Args = std::move(Args);
   return 0;
   return 0;
 }
 }

+ 8 - 0
tools/clang/include/clang/SPIRV/EmitSPIRVAction.h

@@ -11,12 +11,20 @@
 
 
 #include "clang/Frontend/FrontendAction.h"
 #include "clang/Frontend/FrontendAction.h"
 
 
+#include "clang/SPIRV/EmitSPIRVOptions.h"
+
 namespace clang {
 namespace clang {
 
 
 class EmitSPIRVAction : public ASTFrontendAction {
 class EmitSPIRVAction : public ASTFrontendAction {
+public:
+  EmitSPIRVAction(const EmitSPIRVOptions &opts) : options(opts) {}
+
 protected:
 protected:
   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
                                                  StringRef InFile) override;
                                                  StringRef InFile) override;
+
+private:
+  EmitSPIRVOptions options;
 };
 };
 
 
 } // end namespace clang
 } // end namespace clang

+ 21 - 0
tools/clang/include/clang/SPIRV/EmitSPIRVOptions.h

@@ -0,0 +1,21 @@
+//===-- EmitSPIRVOptions.h - Options for SPIR-V CodeGen ---------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SPIRV_EMITSPIRVOPTIONS_H
+#define LLVM_CLANG_SPIRV_EMITSPIRVOPTIONS_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+/// Structs for controlling behaviors of SPIR-V codegen.
+struct EmitSPIRVOptions {
+  llvm::StringRef stageIoOrder;
+};
+} // end namespace clang
+
+#endif

+ 7 - 6
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -361,12 +361,13 @@ bool DeclResultIdMapper::finalizeStageIOLocations(bool forInput) {
     }
     }
   }
   }
 
 
-  // Sort stage input/output variables alphabetically
-  const auto comp = [](const StageVar *a, const StageVar *b) {
-    return a->getSemanticStr() < b->getSemanticStr();
-  };
-
-  std::sort(vars.begin(), vars.end(), comp);
+  if (spirvOptions.stageIoOrder == "alpha") {
+    // Sort stage input/output variables alphabetically
+    std::sort(vars.begin(), vars.end(),
+              [](const StageVar *a, const StageVar *b) {
+                return a->getSemanticStr() < b->getSemanticStr();
+              });
+  }
 
 
   for (const auto *var : vars)
   for (const auto *var : vars)
     theBuilder.decorateLocation(var->getSpirvId(), locSet.useNextLoc());
     theBuilder.decorateLocation(var->getSpirvId(), locSet.useNextLoc());

+ 10 - 5
tools/clang/lib/SPIRV/DeclResultIdMapper.h

@@ -17,6 +17,7 @@
 #include "dxc/HLSL/DxilSigPoint.h"
 #include "dxc/HLSL/DxilSigPoint.h"
 #include "spirv/1.0/spirv.hpp11"
 #include "spirv/1.0/spirv.hpp11"
 #include "clang/AST/Attr.h"
 #include "clang/AST/Attr.h"
+#include "clang/SPIRV/EmitSPIRVOptions.h"
 #include "clang/SPIRV/ModuleBuilder.h"
 #include "clang/SPIRV/ModuleBuilder.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/Optional.h"
@@ -115,7 +116,8 @@ private:
 class DeclResultIdMapper {
 class DeclResultIdMapper {
 public:
 public:
   inline DeclResultIdMapper(const hlsl::ShaderModel &stage, ASTContext &context,
   inline DeclResultIdMapper(const hlsl::ShaderModel &stage, ASTContext &context,
-                            ModuleBuilder &builder, DiagnosticsEngine &diag);
+                            ModuleBuilder &builder, DiagnosticsEngine &diag,
+                            const EmitSPIRVOptions &spirvOptions);
 
 
   /// \brief Creates the stage output variables by parsing the semantics
   /// \brief Creates the stage output variables by parsing the semantics
   /// attached to the given function's parameter or return value and returns
   /// attached to the given function's parameter or return value and returns
@@ -236,9 +238,11 @@ private:
 private:
 private:
   const hlsl::ShaderModel &shaderModel;
   const hlsl::ShaderModel &shaderModel;
   ModuleBuilder &theBuilder;
   ModuleBuilder &theBuilder;
-  TypeTranslator typeTranslator;
+  const EmitSPIRVOptions &spirvOptions;
   DiagnosticsEngine &diags;
   DiagnosticsEngine &diags;
 
 
+  TypeTranslator typeTranslator;
+
   uint32_t entryFunctionId;
   uint32_t entryFunctionId;
 
 
   /// Mapping of all Clang AST decls to their <result-id>s.
   /// Mapping of all Clang AST decls to their <result-id>s.
@@ -252,9 +256,10 @@ private:
 DeclResultIdMapper::DeclResultIdMapper(const hlsl::ShaderModel &model,
 DeclResultIdMapper::DeclResultIdMapper(const hlsl::ShaderModel &model,
                                        ASTContext &context,
                                        ASTContext &context,
                                        ModuleBuilder &builder,
                                        ModuleBuilder &builder,
-                                       DiagnosticsEngine &diag)
-    : shaderModel(model), theBuilder(builder),
-      typeTranslator(context, builder, diag), diags(diag), entryFunctionId(0) {}
+                                       DiagnosticsEngine &diag,
+                                       const EmitSPIRVOptions &options)
+    : shaderModel(model), theBuilder(builder), spirvOptions(options),
+      diags(diag), typeTranslator(context, builder, diag), entryFunctionId(0) {}
 
 
 bool DeclResultIdMapper::decorateStageIOLocations() {
 bool DeclResultIdMapper::decorateStageIOLocations() {
   // Try both input and output even if input location assignment failed
   // Try both input and output even if input location assignment failed

+ 1 - 1
tools/clang/lib/SPIRV/EmitSPIRVAction.cpp

@@ -18,6 +18,6 @@ namespace clang {
 
 
 std::unique_ptr<ASTConsumer>
 std::unique_ptr<ASTConsumer>
 EmitSPIRVAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
 EmitSPIRVAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
-  return llvm::make_unique<spirv::SPIRVEmitter>(CI);
+  return llvm::make_unique<spirv::SPIRVEmitter>(CI, options);
 }
 }
 } // end namespace clang
 } // end namespace clang

+ 4 - 3
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -135,14 +135,15 @@ bool isLoopStmt(const Stmt *stmt) {
 
 
 } // namespace
 } // namespace
 
 
-SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci)
+SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
+                           const EmitSPIRVOptions &options)
     : theCompilerInstance(ci), astContext(ci.getASTContext()),
     : theCompilerInstance(ci), astContext(ci.getASTContext()),
-      diags(ci.getDiagnostics()),
+      diags(ci.getDiagnostics()), spirvOptions(options),
       entryFunctionName(ci.getCodeGenOpts().HLSLEntryFunction),
       entryFunctionName(ci.getCodeGenOpts().HLSLEntryFunction),
       shaderModel(*hlsl::ShaderModel::GetByName(
       shaderModel(*hlsl::ShaderModel::GetByName(
           ci.getCodeGenOpts().HLSLProfile.c_str())),
           ci.getCodeGenOpts().HLSLProfile.c_str())),
       theContext(), theBuilder(&theContext),
       theContext(), theBuilder(&theContext),
-      declIdMapper(shaderModel, astContext, theBuilder, diags),
+      declIdMapper(shaderModel, astContext, theBuilder, diags, spirvOptions),
       typeTranslator(astContext, theBuilder, diags), entryFunctionId(0),
       typeTranslator(astContext, theBuilder, diags), entryFunctionId(0),
       curFunction(nullptr) {
       curFunction(nullptr) {
   if (shaderModel.GetKind() == hlsl::ShaderModel::Kind::Invalid)
   if (shaderModel.GetKind() == hlsl::ShaderModel::Kind::Invalid)

+ 4 - 1
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -26,6 +26,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInstance.h"
+#include "clang/SPIRV/EmitSPIRVOptions.h"
 #include "clang/SPIRV/ModuleBuilder.h"
 #include "clang/SPIRV/ModuleBuilder.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SetVector.h"
@@ -42,7 +43,7 @@ namespace spirv {
 /// through the AST is done manually instead of using ASTConsumer's harness.
 /// through the AST is done manually instead of using ASTConsumer's harness.
 class SPIRVEmitter : public ASTConsumer {
 class SPIRVEmitter : public ASTConsumer {
 public:
 public:
-  explicit SPIRVEmitter(CompilerInstance &ci);
+  explicit SPIRVEmitter(CompilerInstance &ci, const EmitSPIRVOptions &options);
 
 
   void HandleTranslationUnit(ASTContext &context) override;
   void HandleTranslationUnit(ASTContext &context) override;
 
 
@@ -433,6 +434,8 @@ private:
   ASTContext &astContext;
   ASTContext &astContext;
   DiagnosticsEngine &diags;
   DiagnosticsEngine &diags;
 
 
+  EmitSPIRVOptions spirvOptions;
+
   /// Entry function name and shader stage. Both of them are derived from the
   /// Entry function name and shader stage. Both of them are derived from the
   /// command line and should be const.
   /// command line and should be const.
   const llvm::StringRef entryFunctionName;
   const llvm::StringRef entryFunctionName;

+ 2 - 2
tools/clang/test/CodeGenSPIRV/passthru-vs.hlsl2spv

@@ -37,8 +37,8 @@ PSInput VSmain(float4 position: POSITION, float4 color: COLOR) {
 // OpName %color "color"
 // OpName %color "color"
 // OpName %result "result"
 // OpName %result "result"
 // OpDecorate %gl_Position BuiltIn Position
 // OpDecorate %gl_Position BuiltIn Position
-// OpDecorate %in_var_COLOR Location 0
-// OpDecorate %in_var_POSITION Location 1
+// OpDecorate %in_var_POSITION Location 0
+// OpDecorate %in_var_COLOR Location 1
 // OpDecorate %out_var_COLOR Location 0
 // OpDecorate %out_var_COLOR Location 0
 // %int = OpTypeInt 32 1
 // %int = OpTypeInt 32 1
 // %void = OpTypeVoid
 // %void = OpTypeVoid

+ 1 - 1
tools/clang/test/CodeGenSPIRV/semantic.arbitrary.location.hlsl → tools/clang/test/CodeGenSPIRV/semantic.arbitrary.location.alpha.hlsl

@@ -1,4 +1,4 @@
-// Run: %dxc -T vs_6_0 -E main
+// Run: %dxc -T vs_6_0 -E main -fvk-stage-io-order=alpha
 
 
 struct S {
 struct S {
     float c: C;
     float c: C;

+ 44 - 0
tools/clang/test/CodeGenSPIRV/semantic.arbitrary.location.decl.hlsl

@@ -0,0 +1,44 @@
+// Run: %dxc -T vs_6_0 -E main
+
+struct S {
+    float c: C;
+    float a: A;
+    float b: B;
+};
+
+struct T {
+    float e: E;
+    S     s;
+    float d: D;
+};
+
+// CHECK:      OpDecorate %in_var_N Location 0
+// CHECK-NEXT: OpDecorate %in_var_E Location 1
+// CHECK-NEXT: OpDecorate %in_var_C Location 2
+// CHECK-NEXT: OpDecorate %in_var_A Location 3
+// CHECK-NEXT: OpDecorate %in_var_B Location 4
+// CHECK-NEXT: OpDecorate %in_var_D Location 5
+// CHECK-NEXT: OpDecorate %in_var_M Location 6
+
+// CHECK-NEXT: OpDecorate %out_var_E Location 0
+// CHECK-NEXT: OpDecorate %out_var_C Location 1
+// CHECK-NEXT: OpDecorate %out_var_A Location 2
+// CHECK-NEXT: OpDecorate %out_var_B Location 3
+// CHECK-NEXT: OpDecorate %out_var_D Location 4
+// CHECK-NEXT: OpDecorate %out_var_Q Location 5
+// CHECK-NEXT: OpDecorate %out_var_P Location 6
+
+// Input semantics by declaration order: N, E, C, A, B, D, M
+//                 by alphabetic order:  A, B, C, D, E, M, N
+
+// Output semantics by declaration order: E, C, A, B, D, Q, P
+//                  by alphabetic order:  A, B, C, D, E, P, Q
+
+void main(in  float input1 : N,
+          in  T     input2 ,
+          in  float input3 : M,
+          out T     output1,
+          out float output2: Q,
+          out float output3: P
+         ) {
+}

+ 3 - 3
tools/clang/test/CodeGenSPIRV/vk.location.exp-in.hlsl

@@ -28,7 +28,7 @@ float main([[vk::location(0)]] in  uint   m: M, // On function parameter --- M -
 // CHECK: OpDecorate %in_var_B Location 1
 // CHECK: OpDecorate %in_var_B Location 1
 // CHECK: OpDecorate %in_var_A Location 2
 // CHECK: OpDecorate %in_var_A Location 2
 
 
-// Alphabetical assignment
-// CHECK: OpDecorate %out_var_C Location 0
+// Declaration order assignment
+// CHECK: OpDecorate %out_var_R Location 0
 // CHECK: OpDecorate %out_var_N Location 1
 // CHECK: OpDecorate %out_var_N Location 1
-// CHECK: OpDecorate %out_var_R Location 2
+// CHECK: OpDecorate %out_var_C Location 2

+ 3 - 4
tools/clang/test/CodeGenSPIRV/vk.location.exp-out.hlsl

@@ -24,13 +24,12 @@ float main(                    in  uint   m: M,
     return 1.0;
     return 1.0;
 }
 }
 
 
-// Alphabetical assignment
-// CHECK: OpDecorate %in_var_A Location 0
+// Declaration order assignment
+// CHECK: OpDecorate %in_var_M Location 0
 // CHECK: OpDecorate %in_var_B Location 1
 // CHECK: OpDecorate %in_var_B Location 1
-// CHECK: OpDecorate %in_var_M Location 2
+// CHECK: OpDecorate %in_var_A Location 2
 
 
 // Explicit assignment
 // Explicit assignment
 // CHECK: OpDecorate %out_var_R Location 2
 // CHECK: OpDecorate %out_var_R Location 2
 // CHECK: OpDecorate %out_var_N Location 0
 // CHECK: OpDecorate %out_var_N Location 0
 // CHECK: OpDecorate %out_var_C Location 1
 // CHECK: OpDecorate %out_var_C Location 1
-

+ 0 - 5
tools/clang/tools/dxc/dxc.cpp

@@ -970,11 +970,6 @@ int __cdecl wmain(int argc, const wchar_t **argv_) {
       fprintf(stderr, "-spirv requires -Fo for output object file name.");
       fprintf(stderr, "-spirv requires -Fo for output object file name.");
       return 1;
       return 1;
     }
     }
-#else
-    if (dxcOpts.GenSPIRV) {
-      fprintf(stderr, "SPIR-V codegen not configured via ENABLE_SPIRV_CODEGEN");
-      return 1;
-    }
 #endif
 #endif
     // SPIRV change ends
     // SPIRV change ends
 
 

+ 3 - 1
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -462,7 +462,9 @@ public:
       // SPIRV change starts
       // SPIRV change starts
 #ifdef ENABLE_SPIRV_CODEGEN
 #ifdef ENABLE_SPIRV_CODEGEN
       else if (opts.GenSPIRV) {
       else if (opts.GenSPIRV) {
-          clang::EmitSPIRVAction action;
+          clang::EmitSPIRVOptions spirvOpts;
+          spirvOpts.stageIoOrder = opts.VkStageIoOrder;
+          clang::EmitSPIRVAction action(spirvOpts);
           FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
           FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
           action.BeginSourceFile(compiler, file);
           action.BeginSourceFile(compiler, file);
           action.Execute();
           action.Execute();

+ 5 - 2
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -286,8 +286,11 @@ TEST_F(FileTest, SemanticIsFrontFacePS) {
   runFileTest("semantic.is-front-face.ps.hlsl");
   runFileTest("semantic.is-front-face.ps.hlsl");
 }
 }
 TEST_F(FileTest, SemanticArbitrary) { runFileTest("semantic.arbitrary.hlsl"); }
 TEST_F(FileTest, SemanticArbitrary) { runFileTest("semantic.arbitrary.hlsl"); }
-TEST_F(FileTest, SemanticArbitraryLocation) {
-  runFileTest("semantic.arbitrary.location.hlsl");
+TEST_F(FileTest, SemanticArbitraryDeclLocation) {
+  runFileTest("semantic.arbitrary.location.decl.hlsl");
+}
+TEST_F(FileTest, SemanticArbitraryAlphaLocation) {
+  runFileTest("semantic.arbitrary.location.alpha.hlsl");
 }
 }
 TEST_F(FileTest, SemanticDuplication) {
 TEST_F(FileTest, SemanticDuplication) {
   runFileTest("semantic.duplication.hlsl", /*expectSuccess*/ false);
   runFileTest("semantic.duplication.hlsl", /*expectSuccess*/ false);

+ 3 - 3
tools/clang/unittests/SPIRV/FileTestFixture.cpp

@@ -46,8 +46,8 @@ bool FileTest::parseInputFile() {
   if (runCmdStartPos != std::string::npos) {
   if (runCmdStartPos != std::string::npos) {
     const auto runCmdEndPos = checkCommands.find('\n', runCmdStartPos);
     const auto runCmdEndPos = checkCommands.find('\n', runCmdStartPos);
     const auto runCommand = checkCommands.substr(runCmdStartPos, runCmdEndPos);
     const auto runCommand = checkCommands.substr(runCmdStartPos, runCmdEndPos);
-    if (!utils::processRunCommandArgs(runCommand, &targetProfile,
-                                      &entryPoint)) {
+    if (!utils::processRunCommandArgs(runCommand, &targetProfile, &entryPoint,
+                                      &restArgs)) {
       // An error has occured when parsing the Run command.
       // An error has occured when parsing the Run command.
       return false;
       return false;
     }
     }
@@ -71,7 +71,7 @@ void FileTest::runFileTest(llvm::StringRef filename, bool expectSuccess,
 
 
   // Feed the HLSL source into the Compiler.
   // Feed the HLSL source into the Compiler.
   const bool compileOk = utils::runCompilerWithSpirvGeneration(
   const bool compileOk = utils::runCompilerWithSpirvGeneration(
-      inputFilePath, entryPoint, targetProfile, &generatedBinary,
+      inputFilePath, entryPoint, targetProfile, restArgs, &generatedBinary,
       &errorMessages);
       &errorMessages);
 
 
   effcee::Result result(effcee::Result::Status::Ok);
   effcee::Result result(effcee::Result::Status::Ok);

+ 1 - 0
tools/clang/unittests/SPIRV/FileTestFixture.h

@@ -34,6 +34,7 @@ private:
 
 
   std::string targetProfile;             ///< Target profile (argument of -T)
   std::string targetProfile;             ///< Target profile (argument of -T)
   std::string entryPoint;                ///< Entry point name (argument of -E)
   std::string entryPoint;                ///< Entry point name (argument of -E)
+  std::string restArgs;                  ///< All the other arguments
   std::string inputFilePath;             ///< Path to the input test file
   std::string inputFilePath;             ///< Path to the input test file
   std::vector<uint32_t> generatedBinary; ///< The generated SPIR-V Binary
   std::vector<uint32_t> generatedBinary; ///< The generated SPIR-V Binary
   std::string checkCommands;             ///< CHECK commands that verify output
   std::string checkCommands;             ///< CHECK commands that verify output

+ 17 - 8
tools/clang/unittests/SPIRV/FileTestUtils.cpp

@@ -10,6 +10,7 @@
 #include "FileTestUtils.h"
 #include "FileTestUtils.h"
 
 
 #include <algorithm>
 #include <algorithm>
+#include <sstream>
 
 
 #include "SpirvTestOptions.h"
 #include "SpirvTestOptions.h"
 #include "gtest/gtest.h"
 #include "gtest/gtest.h"
@@ -40,24 +41,29 @@ bool validateSpirvBinary(std::vector<uint32_t> &binary) {
 }
 }
 
 
 bool processRunCommandArgs(const llvm::StringRef runCommandLine,
 bool processRunCommandArgs(const llvm::StringRef runCommandLine,
-                           std::string *targetProfile,
-                           std::string *entryPoint) {
+                           std::string *targetProfile, std::string *entryPoint,
+                           std::string *restArgs) {
   std::istringstream buf(runCommandLine);
   std::istringstream buf(runCommandLine);
   std::istream_iterator<std::string> start(buf), end;
   std::istream_iterator<std::string> start(buf), end;
   std::vector<std::string> tokens(start, end);
   std::vector<std::string> tokens(start, end);
-  if (tokens[1].find("Run") == std::string::npos ||
+  if (tokens.size() < 3 || tokens[1].find("Run") == std::string::npos ||
       tokens[2].find("%dxc") == std::string::npos) {
       tokens[2].find("%dxc") == std::string::npos) {
     fprintf(stderr, "The only supported format is: \"// Run: %%dxc -T "
     fprintf(stderr, "The only supported format is: \"// Run: %%dxc -T "
                     "<profile> -E <entry>\"\n");
                     "<profile> -E <entry>\"\n");
     return false;
     return false;
   }
   }
 
 
-  for (size_t i = 0; i < tokens.size(); ++i) {
-    if (tokens[i] == "-T" && i + 1 < tokens.size())
-      *targetProfile = tokens[i + 1];
-    else if (tokens[i] == "-E" && i + 1 < tokens.size())
-      *entryPoint = tokens[i + 1];
+  std::ostringstream rest;
+  for (uint32_t i = 3; i < tokens.size(); ++i) {
+    if (tokens[i] == "-T" && (++i) < tokens.size())
+      *targetProfile = tokens[i];
+    else if (tokens[i] == "-E" && (++i) < tokens.size())
+      *entryPoint = tokens[i];
+    else
+      rest << (restArgs->empty() ? "" : " ") << tokens[i];
   }
   }
+  *restArgs = rest.str();
+
   if (targetProfile->empty()) {
   if (targetProfile->empty()) {
     fprintf(stderr, "Error: Missing target profile argument (-T).\n");
     fprintf(stderr, "Error: Missing target profile argument (-T).\n");
     return false;
     return false;
@@ -100,11 +106,13 @@ std::string getAbsPathOfInputDataFile(const llvm::StringRef filename) {
 bool runCompilerWithSpirvGeneration(const llvm::StringRef inputFilePath,
 bool runCompilerWithSpirvGeneration(const llvm::StringRef inputFilePath,
                                     const llvm::StringRef entryPoint,
                                     const llvm::StringRef entryPoint,
                                     const llvm::StringRef targetProfile,
                                     const llvm::StringRef targetProfile,
+                                    const llvm::StringRef restArgs,
                                     std::vector<uint32_t> *generatedBinary,
                                     std::vector<uint32_t> *generatedBinary,
                                     std::string *errorMessages) {
                                     std::string *errorMessages) {
   std::wstring srcFile(inputFilePath.begin(), inputFilePath.end());
   std::wstring srcFile(inputFilePath.begin(), inputFilePath.end());
   std::wstring entry(entryPoint.begin(), entryPoint.end());
   std::wstring entry(entryPoint.begin(), entryPoint.end());
   std::wstring profile(targetProfile.begin(), targetProfile.end());
   std::wstring profile(targetProfile.begin(), targetProfile.end());
+  std::wstring rest(restArgs.begin(), restArgs.end());
   bool success = true;
   bool success = true;
 
 
   try {
   try {
@@ -126,6 +134,7 @@ bool runCompilerWithSpirvGeneration(const llvm::StringRef inputFilePath,
     flags.push_back(L"-T");
     flags.push_back(L"-T");
     flags.push_back(profile.c_str());
     flags.push_back(profile.c_str());
     flags.push_back(L"-spirv");
     flags.push_back(L"-spirv");
+    flags.push_back(rest.c_str());
 
 
     IFT(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
     IFT(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
     IFT(pLibrary->CreateBlobFromFile(srcFile.c_str(), nullptr, &pSource));
     IFT(pLibrary->CreateBlobFromFile(srcFile.c_str(), nullptr, &pSource));

+ 4 - 2
tools/clang/unittests/SPIRV/FileTestUtils.h

@@ -35,10 +35,11 @@ bool disassembleSpirvBinary(std::vector<uint32_t> &binary,
 bool validateSpirvBinary(std::vector<uint32_t> &binary);
 bool validateSpirvBinary(std::vector<uint32_t> &binary);
 
 
 /// \brief Parses the Target Profile and Entry Point from the Run command
 /// \brief Parses the Target Profile and Entry Point from the Run command
-/// Returns the target profile and entry point via arguments.
+/// Returns the target profile, entry point, and the rest via arguments.
 /// Returns true on success, and false otherwise.
 /// Returns true on success, and false otherwise.
 bool processRunCommandArgs(const llvm::StringRef runCommandLine,
 bool processRunCommandArgs(const llvm::StringRef runCommandLine,
-                           std::string *targetProfile, std::string *entryPoint);
+                           std::string *targetProfile, std::string *entryPoint,
+                           std::string *restArgs);
 
 
 /// \brief Converts an IDxcBlob into a vector of 32-bit unsigned integers which
 /// \brief Converts an IDxcBlob into a vector of 32-bit unsigned integers which
 /// is returned via the 'binaryWords' argument.
 /// is returned via the 'binaryWords' argument.
@@ -57,6 +58,7 @@ std::string getAbsPathOfInputDataFile(const llvm::StringRef filename);
 bool runCompilerWithSpirvGeneration(const llvm::StringRef inputFilePath,
 bool runCompilerWithSpirvGeneration(const llvm::StringRef inputFilePath,
                                     const llvm::StringRef entryPoint,
                                     const llvm::StringRef entryPoint,
                                     const llvm::StringRef targetProfile,
                                     const llvm::StringRef targetProfile,
+                                    const llvm::StringRef restArgs,
                                     std::vector<uint32_t> *generatedBinary,
                                     std::vector<uint32_t> *generatedBinary,
                                     std::string *errorMessages);
                                     std::string *errorMessages);
 
 

+ 3 - 2
tools/clang/unittests/SPIRV/WholeFileTestFixture.cpp

@@ -31,7 +31,8 @@ bool WholeFileTest::parseInputFile() {
     for (std::string line; std::getline(inputFile, line);) {
     for (std::string line; std::getline(inputFile, line);) {
       if (line.find(hlslStartLabel) != std::string::npos) {
       if (line.find(hlslStartLabel) != std::string::npos) {
         foundRunCommand = true;
         foundRunCommand = true;
-        if (!utils::processRunCommandArgs(line, &targetProfile, &entryPoint)) {
+        if (!utils::processRunCommandArgs(line, &targetProfile, &entryPoint,
+                                          &restArgs)) {
           // An error has occured when parsing the Run command.
           // An error has occured when parsing the Run command.
           return false;
           return false;
         }
         }
@@ -94,7 +95,7 @@ void WholeFileTest::runWholeFileTest(llvm::StringRef filename,
 
 
   // Feed the HLSL source into the Compiler.
   // Feed the HLSL source into the Compiler.
   ASSERT_TRUE(utils::runCompilerWithSpirvGeneration(
   ASSERT_TRUE(utils::runCompilerWithSpirvGeneration(
-      inputFilePath, entryPoint, targetProfile, &generatedBinary,
+      inputFilePath, entryPoint, targetProfile, restArgs, &generatedBinary,
       &errorMessages));
       &errorMessages));
 
 
   // Disassemble the generated SPIR-V binary.
   // Disassemble the generated SPIR-V binary.

+ 1 - 0
tools/clang/unittests/SPIRV/WholeFileTestFixture.h

@@ -58,6 +58,7 @@ private:
 
 
   std::string targetProfile;             ///< Target profile (argument of -T)
   std::string targetProfile;             ///< Target profile (argument of -T)
   std::string entryPoint;                ///< Entry point name (argument of -E)
   std::string entryPoint;                ///< Entry point name (argument of -E)
+  std::string restArgs;                  ///< All the other arguments
   std::string inputFilePath;             ///< Path to the input test file
   std::string inputFilePath;             ///< Path to the input test file
   std::vector<uint32_t> generatedBinary; ///< The generated SPIR-V Binary
   std::vector<uint32_t> generatedBinary; ///< The generated SPIR-V Binary
   std::string expectedSpirvAsm;          ///< Expected SPIR-V parsed from input
   std::string expectedSpirvAsm;          ///< Expected SPIR-V parsed from input