Explorar el Código

[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 hace 8 años
padre
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.
 
-Variable definition
-+++++++++++++++++++
-
 Variables are defined in HLSL using the following
 `syntax <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509706(v=vs.85).aspx>`_
 rules::
@@ -331,7 +328,7 @@ to ``Location`` 1.
 
 [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,
 for a certain shader stage, one SigPoint using the explicit approach while the
 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
 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
-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.
 
 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 AstDump; // OPT_ast_dump
-  bool GenSPIRV; // OPT_spirv // SPIRV change
   bool ColorCodeAssembly; // OPT_Cc
   bool CodeGenHighLevel; // OPT_fcgl
   bool DebugInfo; // OPT__SLASH_Zi
@@ -157,6 +156,13 @@ public:
   bool DisaseembleHex; //OPT_Lx
   bool IsRootSignatureProfile();
   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

+ 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 hlslcore_Group : OptionGroup<"HLSL Core">, HelpText<"Common Options">;
 
+def spirv_Group : OptionGroup<"SPIR-V CodeGen">, HelpText<"SPIR-V CodeGen Options">; // SPIRV Change
+
 //////////////////////////////////////////////////////////////////////////////
 // Options
 
@@ -209,8 +211,6 @@ def _help_question : Flag<["-", "/"], "?">, Flags<[DriverOption]>, Alias<help>;
 
 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
-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]>,
   HelpText<"External DLL name to load for compiler support">;
 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.">;
 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.
 

+ 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.Preprocess = Args.getLastArgValue(OPT_P);
   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.DebugInfo = Args.hasFlag(OPT__SLASH_Zi, 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;
   }
 
+  // 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);
   return 0;
 }

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

@@ -11,12 +11,20 @@
 
 #include "clang/Frontend/FrontendAction.h"
 
+#include "clang/SPIRV/EmitSPIRVOptions.h"
+
 namespace clang {
 
 class EmitSPIRVAction : public ASTFrontendAction {
+public:
+  EmitSPIRVAction(const EmitSPIRVOptions &opts) : options(opts) {}
+
 protected:
   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
                                                  StringRef InFile) override;
+
+private:
+  EmitSPIRVOptions options;
 };
 
 } // 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)
     theBuilder.decorateLocation(var->getSpirvId(), locSet.useNextLoc());

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

@@ -17,6 +17,7 @@
 #include "dxc/HLSL/DxilSigPoint.h"
 #include "spirv/1.0/spirv.hpp11"
 #include "clang/AST/Attr.h"
+#include "clang/SPIRV/EmitSPIRVOptions.h"
 #include "clang/SPIRV/ModuleBuilder.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/Optional.h"
@@ -115,7 +116,8 @@ private:
 class DeclResultIdMapper {
 public:
   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
   /// attached to the given function's parameter or return value and returns
@@ -236,9 +238,11 @@ private:
 private:
   const hlsl::ShaderModel &shaderModel;
   ModuleBuilder &theBuilder;
-  TypeTranslator typeTranslator;
+  const EmitSPIRVOptions &spirvOptions;
   DiagnosticsEngine &diags;
 
+  TypeTranslator typeTranslator;
+
   uint32_t entryFunctionId;
 
   /// Mapping of all Clang AST decls to their <result-id>s.
@@ -252,9 +256,10 @@ private:
 DeclResultIdMapper::DeclResultIdMapper(const hlsl::ShaderModel &model,
                                        ASTContext &context,
                                        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() {
   // 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>
 EmitSPIRVAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
-  return llvm::make_unique<spirv::SPIRVEmitter>(CI);
+  return llvm::make_unique<spirv::SPIRVEmitter>(CI, options);
 }
 } // end namespace clang

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

@@ -135,14 +135,15 @@ bool isLoopStmt(const Stmt *stmt) {
 
 } // namespace
 
-SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci)
+SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
+                           const EmitSPIRVOptions &options)
     : theCompilerInstance(ci), astContext(ci.getASTContext()),
-      diags(ci.getDiagnostics()),
+      diags(ci.getDiagnostics()), spirvOptions(options),
       entryFunctionName(ci.getCodeGenOpts().HLSLEntryFunction),
       shaderModel(*hlsl::ShaderModel::GetByName(
           ci.getCodeGenOpts().HLSLProfile.c_str())),
       theContext(), theBuilder(&theContext),
-      declIdMapper(shaderModel, astContext, theBuilder, diags),
+      declIdMapper(shaderModel, astContext, theBuilder, diags, spirvOptions),
       typeTranslator(astContext, theBuilder, diags), entryFunctionId(0),
       curFunction(nullptr) {
   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/Basic/Diagnostic.h"
 #include "clang/Frontend/CompilerInstance.h"
+#include "clang/SPIRV/EmitSPIRVOptions.h"
 #include "clang/SPIRV/ModuleBuilder.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
@@ -42,7 +43,7 @@ namespace spirv {
 /// through the AST is done manually instead of using ASTConsumer's harness.
 class SPIRVEmitter : public ASTConsumer {
 public:
-  explicit SPIRVEmitter(CompilerInstance &ci);
+  explicit SPIRVEmitter(CompilerInstance &ci, const EmitSPIRVOptions &options);
 
   void HandleTranslationUnit(ASTContext &context) override;
 
@@ -433,6 +434,8 @@ private:
   ASTContext &astContext;
   DiagnosticsEngine &diags;
 
+  EmitSPIRVOptions spirvOptions;
+
   /// Entry function name and shader stage. Both of them are derived from the
   /// command line and should be const.
   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 %result "result"
 // 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
 // %int = OpTypeInt 32 1
 // %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 {
     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_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_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;
 }
 
-// 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_M Location 2
+// CHECK: OpDecorate %in_var_A Location 2
 
 // Explicit assignment
 // CHECK: OpDecorate %out_var_R Location 2
 // CHECK: OpDecorate %out_var_N Location 0
 // 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.");
       return 1;
     }
-#else
-    if (dxcOpts.GenSPIRV) {
-      fprintf(stderr, "SPIR-V codegen not configured via ENABLE_SPIRV_CODEGEN");
-      return 1;
-    }
 #endif
     // SPIRV change ends
 

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

@@ -462,7 +462,9 @@ public:
       // SPIRV change starts
 #ifdef ENABLE_SPIRV_CODEGEN
       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);
           action.BeginSourceFile(compiler, file);
           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");
 }
 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) {
   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) {
     const auto runCmdEndPos = checkCommands.find('\n', runCmdStartPos);
     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.
       return false;
     }
@@ -71,7 +71,7 @@ void FileTest::runFileTest(llvm::StringRef filename, bool expectSuccess,
 
   // Feed the HLSL source into the Compiler.
   const bool compileOk = utils::runCompilerWithSpirvGeneration(
-      inputFilePath, entryPoint, targetProfile, &generatedBinary,
+      inputFilePath, entryPoint, targetProfile, restArgs, &generatedBinary,
       &errorMessages);
 
   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 entryPoint;                ///< Entry point name (argument of -E)
+  std::string restArgs;                  ///< All the other arguments
   std::string inputFilePath;             ///< Path to the input test file
   std::vector<uint32_t> generatedBinary; ///< The generated SPIR-V Binary
   std::string checkCommands;             ///< CHECK commands that verify output

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

@@ -10,6 +10,7 @@
 #include "FileTestUtils.h"
 
 #include <algorithm>
+#include <sstream>
 
 #include "SpirvTestOptions.h"
 #include "gtest/gtest.h"
@@ -40,24 +41,29 @@ bool validateSpirvBinary(std::vector<uint32_t> &binary) {
 }
 
 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::istream_iterator<std::string> start(buf), 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) {
     fprintf(stderr, "The only supported format is: \"// Run: %%dxc -T "
                     "<profile> -E <entry>\"\n");
     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()) {
     fprintf(stderr, "Error: Missing target profile argument (-T).\n");
     return false;
@@ -100,11 +106,13 @@ std::string getAbsPathOfInputDataFile(const llvm::StringRef filename) {
 bool runCompilerWithSpirvGeneration(const llvm::StringRef inputFilePath,
                                     const llvm::StringRef entryPoint,
                                     const llvm::StringRef targetProfile,
+                                    const llvm::StringRef restArgs,
                                     std::vector<uint32_t> *generatedBinary,
                                     std::string *errorMessages) {
   std::wstring srcFile(inputFilePath.begin(), inputFilePath.end());
   std::wstring entry(entryPoint.begin(), entryPoint.end());
   std::wstring profile(targetProfile.begin(), targetProfile.end());
+  std::wstring rest(restArgs.begin(), restArgs.end());
   bool success = true;
 
   try {
@@ -126,6 +134,7 @@ bool runCompilerWithSpirvGeneration(const llvm::StringRef inputFilePath,
     flags.push_back(L"-T");
     flags.push_back(profile.c_str());
     flags.push_back(L"-spirv");
+    flags.push_back(rest.c_str());
 
     IFT(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
     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);
 
 /// \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.
 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
 /// is returned via the 'binaryWords' argument.
@@ -57,6 +58,7 @@ std::string getAbsPathOfInputDataFile(const llvm::StringRef filename);
 bool runCompilerWithSpirvGeneration(const llvm::StringRef inputFilePath,
                                     const llvm::StringRef entryPoint,
                                     const llvm::StringRef targetProfile,
+                                    const llvm::StringRef restArgs,
                                     std::vector<uint32_t> *generatedBinary,
                                     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);) {
       if (line.find(hlslStartLabel) != std::string::npos) {
         foundRunCommand = true;
-        if (!utils::processRunCommandArgs(line, &targetProfile, &entryPoint)) {
+        if (!utils::processRunCommandArgs(line, &targetProfile, &entryPoint,
+                                          &restArgs)) {
           // An error has occured when parsing the Run command.
           return false;
         }
@@ -94,7 +95,7 @@ void WholeFileTest::runWholeFileTest(llvm::StringRef filename,
 
   // Feed the HLSL source into the Compiler.
   ASSERT_TRUE(utils::runCompilerWithSpirvGeneration(
-      inputFilePath, entryPoint, targetProfile, &generatedBinary,
+      inputFilePath, entryPoint, targetProfile, restArgs, &generatedBinary,
       &errorMessages));
 
   // 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 entryPoint;                ///< Entry point name (argument of -E)
+  std::string restArgs;                  ///< All the other arguments
   std::string inputFilePath;             ///< Path to the input test file
   std::vector<uint32_t> generatedBinary; ///< The generated SPIR-V Binary
   std::string expectedSpirvAsm;          ///< Expected SPIR-V parsed from input