Преглед изворни кода

Merge 'master' into dxil-v1.0

Tex Riddell пре 8 година
родитељ
комит
220f78a557

+ 19 - 18
README.md

@@ -1,6 +1,8 @@
 # DirectX Shader Compiler
 
-The DirectX Shader Compiler is a compiler and related set of tools used to compile High-Level Shader Language (HLSL) programs into DirectX Intermediate Language (DXIL) representation. Applications that make use of DirectX for graphics, games, and computation can use it to generate shader programs.
+The DirectX Shader Compiler project includes a compiler and related tools used to compile High-Level Shader Language (HLSL) programs into DirectX Intermediate Language (DXIL) representation. Applications that make use of DirectX for graphics, games, and computation can use it to generate shader programs.
+
+For more information, see the [Wiki](https://github.com/Microsoft/DirectXShaderCompiler/wiki).
 
 ## Features and Goals
 
@@ -23,19 +25,21 @@ The goal of the project is to allow the broader community of shader developers t
 Before you build, you will need to have some additional software installed.
 
 * [Git](http://git-scm.com/downloads).
-* [Visual Studio 2015](https://www.visualstudio.com/downloads). Update 3 is the supported version. This will install the Windows Development Kit as a side effect. We also need the common tools for visual C++ to get the atl headers (e.g. atlbase.h). In the install options, make sure the following options are checked:
+* [Visual Studio 2015](https://www.visualstudio.com/downloads), Update 3. This will install the Windows Development Kit. In the install options, make sure the following options are checked:
     * Windows 10 SDK (10.0.10240.0)
     * Common Tools for Visual C++ 2015
-* [Windows 10 SDK](https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk). This is needed to build tests that reference the D3D12 runtime.
-* [Windows Driver Kit](https://developer.microsoft.com/en-us/windows/hardware/windows-driver-kit). Or download and install the [Windows Driver Kit 8.1 Update 1](http://www.microsoft.com/en-us/download/details.aspx?id=42273), no need to download and install tests. This will target your common Windows Kits path, on a 64-bit machine this will likely be C:\Program Files (x86)\Windows Kits\8.1. WDK for Windows 10 should also work. This is currently needed to run TAEF tests and build with the TAEF framework.
+* [Windows 10 SDK](https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk). This is needed to build tests that reference the D3D12 runtime. You may get this as part of installing/updating Visual Studio.
+* [Windows Driver Kit](https://developer.microsoft.com/en-us/windows/hardware/windows-driver-kit). No need to download and install tests. This is used to build and run tests.
 * [CMake](https://cmake.org/files/v3.4/cmake-3.4.3-win32-x86.exe). Version 3.4.3 is the supported version. You need not change your PATH variable during installation.
 * [Python](https://www.python.org/downloads/). Version 2.7.x is required, 3.x might work but it's not officially supported. You need not change your PATH variable during installation.
 
-To setup the build environment run the `utils\hct\hctstart.cmd` script passing the path to the source and build directories. For example:
+To setup the build environment run the `utils\hct\hctstart.cmd` script passing the path to the source and build directories from a regular command prompt window. For example:
 
-    git clone <DirectXShaderCompiler repo> C:\DirectXShaderCompiler
-    cd C:\DirectXShaderCompiler
-    utils\hct\hctstart.cmd C:\DirectXShaderCompiler C:\DirectXShaderCompiler.bin
+```
+git clone https://github.com/Microsoft/DirectXShaderCompiler.git C:\DirectXShaderCompiler
+cd C:\DirectXShaderCompiler
+utils\hct\hctstart.cmd C:\DirectXShaderCompiler C:\DirectXShaderCompiler.bin
+```
 
 To create a shortcut to the build environment with the default build directory, double-click on the `utils\hct\hctshortcut.js` file.
 
@@ -47,6 +51,8 @@ You can also clean, build and run tests with this command.
 
     hctcheckin 
 
+To see a list of additional commands available, run `hcthelp`
+
 ## Running Tests
 
 To run tests, open the HLSL Console and run this command after a successful build.
@@ -61,9 +67,11 @@ To run shaders compiled as DXIL, you will need support from the operating system
 
 At the moment, the [Windows 10 Insider Preview Build 15007](https://blogs.windows.com/windowsexperience/2017/01/12/announcing-windows-10-insider-preview-build-15007-pc-mobile/#XqlQ5FZfXw5WVhpS.97) is able to run DXIL shaders.
 
-Drivers indicate support DXIL by reporting support for Shader Model 6, possibly in experimental mode. To enable support in these cases, the [Developer mode](https://msdn.microsoft.com/windows/uwp/get-started/enable-your-device-for-development) setting must be enabled.
+Drivers indicate they can run DXIL by reporting support for Shader Model 6, possibly in experimental mode. To enable support in these cases, the [Developer mode](https://msdn.microsoft.com/windows/uwp/get-started/enable-your-device-for-development) setting must be enabled.
+
+By default, tests will run using the Windows Advanced Rasterization Platform (WARP) adapter. To get the correct version of WARP working, in addition to setting Developer mode, you should install the 'Graphics Tools' optional feature via the Settings app (click the 'Apps' icon, then the 'Manage optional features' link, then 'Add a feature', and select 'Graphics Tools' from the list).
 
-By default, tests will run using the Windows Advanced Rasterization Platform (WARP) adapter. To select the first available adapter that supports D3D12 instead, the parameter /p:"Adapter=*" can be added to the test command line in utils/hct/hcttest.cmd.
+For more information, see this [Wiki page](https://github.com/Microsoft/DirectXShaderCompiler/wiki/Running-Shaders).
 
 ## Making Changes
 
@@ -71,19 +79,12 @@ To make contributions, see the CONTRIBUTING.md file in this project.
 
 ## Documentation
 
-You can find documentation for this project in the docs/ directory. These contain the original LLVM documentation files, as well as two new files worth nothing:
+You can find documentation for this project in the `docs` directory. These contain the original LLVM documentation files, as well as two new files worth nothing:
 
 * HLSLChanges.rst: this is the starting point for how this fork diverges from the original llvm/clang sources
 * DXIL.rst: this file contains the specification for the DXIL format
 * tools/clang/docs/UsingDxc.rst: this file contains a user guide for dxc.exe
 
-## Other Useful Tools
-
-These are recommendations from experience to improve your coding, not official endorsements.
-
-* [Text Macros](https://visualstudiogallery.msdn.microsoft.com/8e2103b6-87cf-4fef-9410-a580c434b602). This adds record/playback for keyboard sequenhces.
-* [clang-format plugin for Visual Studio](http://llvm.org/builds/). This is the code standard we are looking to use.
-
 ## License
 
 DirectX Shader Compiler is distributed under the terms of the MIT license.

+ 1 - 1
docs/DXIL.rst

@@ -2114,7 +2114,7 @@ DECL.NOTUSEDEXTERNAL                  External declaration should not be used
 DECL.USEDEXTERNALFUNCTION             External function must be used
 DECL.USEDINTERNAL                     Internal declaration must be used
 FLOW.DEADLOOP                         Loop must have break
-FLOW.FUNCTIONCALL                     Function call on user defined function with parameter is not permitted
+FLOW.FUNCTIONCALL                     Function with parameter is not permitted
 FLOW.NORECUSION                       Recursion is not permitted
 FLOW.REDUCIBLE                        Execution flow must be reducible
 INSTR.ALLOWED                         Instructions must be of an allowed type

+ 14 - 0
include/dxc/HLSL/DxilContainer.h

@@ -232,6 +232,20 @@ inline const char *GetDxilPartData(const DxilPartHeader *pPart) {
 inline char *GetDxilPartData(DxilPartHeader *pPart) {
   return reinterpret_cast<char *>(pPart + 1);
 }
+/// Gets a part header by fourCC
+DxilPartHeader *GetDxilPartByType(DxilContainerHeader *pHeader,
+                                           DxilFourCC fourCC);
+/// Gets a part header by fourCC 
+const DxilPartHeader *
+GetDxilPartByType(const DxilContainerHeader *pHeader,
+                           DxilFourCC fourCC);
+
+/// Returns valid DxilProgramHeader. nullptr if does not exist.
+DxilProgramHeader *GetDxilProgramHeader(DxilContainerHeader *pHeader, DxilFourCC fourCC);
+
+/// Returns valid DxilProgramHeader. nullptr if does not exist.
+const DxilProgramHeader *
+GetDxilProgramHeader(const DxilContainerHeader *pHeader, DxilFourCC fourCC);
 
 /// Initializes container with the specified values.
 void InitDxilContainer(_Out_ DxilContainerHeader *pHeader, uint32_t partCount,

+ 1 - 1
include/dxc/HLSL/DxilValidation.h

@@ -147,7 +147,7 @@ enum class ValidationRule : unsigned {
 
   // Program flow
   FlowDeadLoop, // Loop must have break
-  FlowFunctionCall, // Function call on user defined function with parameter is not permitted
+  FlowFunctionCall, // Function with parameter is not permitted
   FlowNoRecusion, // Recursion is not permitted
   FlowReducible, // Execution flow must be reducible
 

+ 1 - 1
include/dxc/Support/HLSLOptions.td

@@ -259,7 +259,7 @@ def Fc : JoinedOrSeparate<["-", "/"], "Fc">, MetaVarName<"<file>">, HelpText<"Ou
 def Fh : JoinedOrSeparate<["-", "/"], "Fh">, MetaVarName<"<file>">, HelpText<"Output header file containing object code">, Flags<[DriverOption]>, Group<hlslcomp_Group>;
 def Fe : JoinedOrSeparate<["-", "/"], "Fe">, MetaVarName<"<file>">, HelpText<"Output warnings and errors to a specific file">, Flags<[DriverOption]>, Group<hlslcomp_Group>;
 def Fd : JoinedOrSeparate<["-", "/"], "Fd">, MetaVarName<"<file>">, HelpText<"Extract shader PDB and write to given file">, Flags<[DriverOption]>, Group<hlslcomp_Group>;
-def Vn : JoinedOrSeparate<["-", "/"], "Vn">, HelpText<"Use <name> as variable name in header file">, Flags<[DriverOption]>, Group<hlslcomp_Group>;
+def Vn : JoinedOrSeparate<["-", "/"], "Vn">, MetaVarName<"<name>">, HelpText<"Use <name> as variable name in header file">, Flags<[DriverOption]>, Group<hlslcomp_Group>;
 def Cc : Flag<["-", "/"], "Cc">, HelpText<"Output color coded assembly listings">, Group<hlslcomp_Group>;
 def Ni : Flag<["-", "/"], "Ni">, HelpText<"Output instruction numbers in assembly listings">, Group<hlslcomp_Group>;
 def No : Flag<["-", "/"], "No">, HelpText<"Output instruction byte offsets in assembly listings">, Group<hlslcomp_Group>;

+ 40 - 0
lib/HLSL/DxilContainer.cpp

@@ -10,6 +10,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "dxc/HLSL/DxilContainer.h"
+#include <algorithm>
 
 namespace hlsl {
 
@@ -82,4 +83,43 @@ bool IsValidDxilContainer(const DxilContainerHeader *pHeader, size_t length) {
   return true;
 }
 
+const DxilPartHeader *GetDxilPartByType(const DxilContainerHeader *pHeader, DxilFourCC fourCC) {
+  if (!IsDxilContainerLike(pHeader, pHeader->ContainerSizeInBytes)) {
+    return nullptr;
+  }
+  const DxilPartIterator partIter =
+      find_if(begin(pHeader), end(pHeader), DxilPartIsType(fourCC));
+  if (partIter == end(pHeader)) {
+    return nullptr;
+  }
+  return *partIter;
+}
+
+DxilPartHeader *GetDxilPartByType(DxilContainerHeader *pHeader,
+                                  DxilFourCC fourCC) {
+  return const_cast<DxilPartHeader *>(GetDxilPartByType(
+      static_cast<const DxilContainerHeader *>(pHeader), fourCC));
+}
+
+const DxilProgramHeader *GetDxilProgramHeader(const DxilContainerHeader *pHeader, DxilFourCC fourCC) {
+  if (!IsDxilContainerLike(pHeader, pHeader->ContainerSizeInBytes)) {
+    return nullptr;
+  }
+  const DxilPartHeader *PartHeader = GetDxilPartByType(pHeader, fourCC);
+  if (!PartHeader) {
+    return nullptr;
+  }
+  const DxilProgramHeader *ProgramHeader =
+      reinterpret_cast<const DxilProgramHeader *>(GetDxilPartData(PartHeader));
+  return IsValidDxilProgramHeader(ProgramHeader,
+                                  ProgramHeader->SizeInUint32 * 4)
+             ? ProgramHeader
+             : nullptr;
+}
+
+DxilProgramHeader *GetDxilProgramHeader(DxilContainerHeader *pHeader, DxilFourCC fourCC) {
+  return const_cast<DxilProgramHeader *>(
+      GetDxilProgramHeader(static_cast<const DxilContainerHeader *>(pHeader), fourCC));
+}
+
 } // namespace hlsl

+ 53 - 2
lib/HLSL/DxilGenerationPass.cpp

@@ -2496,6 +2496,39 @@ INITIALIZE_PASS(HLEnsureMetadata, "hlsl-hlensure", "HLSL High-Level Metadata Ens
 ///////////////////////////////////////////////////////////////////////////////
 
 namespace {
+
+Function *StripFunctionParameter(Function *F, DxilModule &DM,
+    DenseMap<const Function *, DISubprogram *> &FunctionDIs) {
+  Module &M = *DM.GetModule();
+  Type *VoidTy = Type::getVoidTy(M.getContext());
+  FunctionType *FT = FunctionType::get(VoidTy, false);
+  for (auto &arg : F->args()) {
+    if (!arg.user_empty())
+      return nullptr;
+  }
+
+  Function *NewFunc = Function::Create(FT, F->getLinkage(), F->getName());
+  M.getFunctionList().insert(F, NewFunc);
+  // Splice the body of the old function right into the new function.
+  NewFunc->getBasicBlockList().splice(NewFunc->begin(), F->getBasicBlockList());
+
+  // Patch the pointer to LLVM function in debug info descriptor.
+  auto DI = FunctionDIs.find(F);
+  if (DI != FunctionDIs.end()) {
+    DISubprogram *SP = DI->second;
+    SP->replaceFunction(NewFunc);
+    // Ensure the map is updated so it can be reused on subsequent argument
+    // promotions of the same function.
+    FunctionDIs.erase(DI);
+    FunctionDIs[NewFunc] = SP;
+  }
+  NewFunc->takeName(F);
+  DM.GetTypeSystem().EraseFunctionAnnotation(F);
+  F->eraseFromParent();
+  DM.GetTypeSystem().AddFunctionAnnotation(NewFunc);
+  return NewFunc;
+}
+
 class DxilEmitMetadata : public ModulePass {
 public:
   static char ID; // Pass identification, replacement for typeid
@@ -2586,8 +2619,26 @@ public:
         }
       }
 
-      M.GetDxilModule().CollectShaderFlags(); // Update flags to reflect any changes.
-      M.GetDxilModule().EmitDxilMetadata();
+      DxilModule &DM = M.GetDxilModule();
+      DenseMap<const Function *, DISubprogram *> FunctionDIs =
+          makeSubprogramMap(M);
+      if (Function *PatchConstantFunc = DM.GetPatchConstantFunction()) {
+        PatchConstantFunc =
+            StripFunctionParameter(PatchConstantFunc, DM, FunctionDIs);
+        if (PatchConstantFunc)
+          DM.SetPatchConstantFunction(PatchConstantFunc);
+      }
+
+      if (Function *EntryFunc = DM.GetEntryFunction()) {
+        StringRef Name = DM.GetEntryFunctionName();
+        EntryFunc->setName(Name);
+        EntryFunc = StripFunctionParameter(EntryFunc, DM, FunctionDIs);
+        if (EntryFunc)
+          DM.SetEntryFunction(EntryFunc);
+      }
+
+      DM.CollectShaderFlags(); // Update flags to reflect any changes.
+      DM.EmitDxilMetadata();
       return true;
     }
 

+ 4 - 7
lib/HLSL/DxilValidation.cpp

@@ -216,7 +216,7 @@ const char *hlsl::GetValidationRuleText(ValidationRule value) {
     case hlsl::ValidationRule::FlowReducible: return "Execution flow must be reducible";
     case hlsl::ValidationRule::FlowNoRecusion: return "Recursion is not permitted";
     case hlsl::ValidationRule::FlowDeadLoop: return "Loop must have break";
-    case hlsl::ValidationRule::FlowFunctionCall: return "Function call on user defined function with parameter %0 is not permitted, it should be inlined";
+    case hlsl::ValidationRule::FlowFunctionCall: return "Function %0 with parameter is not permitted, it should be inlined";
     case hlsl::ValidationRule::DeclDxilNsReserved: return "Declaration '%0' uses a reserved prefix";
     case hlsl::ValidationRule::DeclDxilFnExtern: return "External function '%0' is not a DXIL function";
     case hlsl::ValidationRule::DeclUsedInternal: return "Internal declaration '%0' is unused";
@@ -2520,12 +2520,9 @@ static void ValidateFunction(Function &F, ValidationContext &ValCtx) {
   if (F.isDeclaration()) {
     ValidateExternalFunction(&F, ValCtx);
   } else {
-    if (&F != ValCtx.DxilMod.GetEntryFunction() &&
-        &F != ValCtx.DxilMod.GetPatchConstantFunction()) {
-      if (!F.arg_empty())
-        ValCtx.EmitFormatError(ValidationRule::FlowFunctionCall,
-                               {F.getName().str().c_str()});
-    }
+    if (!F.arg_empty())
+      ValCtx.EmitFormatError(ValidationRule::FlowFunctionCall,
+                             {F.getName().str().c_str()});
 
     DxilFunctionAnnotation *funcAnnotation =
         ValCtx.DxilMod.GetTypeSystem().GetFunctionAnnotation(&F);

+ 13 - 25
lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp

@@ -4133,35 +4133,23 @@ void SROA_Parameter_HLSL::flattenArgument(
 void SROA_Parameter_HLSL::moveFunctionBody(Function *F, Function *flatF) {
   bool updateRetType = F->getReturnType() != flatF->getReturnType();
 
-  // Clone blocks and move instructions.
-  std::unordered_map<Value *, Value *> VMap;
-  Function::BasicBlockListType &blockList = F->getBasicBlockList();
-  for (BasicBlock &BB : blockList) {
-    BasicBlock *NewBB = BasicBlock::Create(BB.getContext(), "", flatF);
-    if (BB.hasName()) NewBB->setName(BB.getName());
-    // Add basic block mapping.
-    VMap[&BB] = NewBB;
-    // Update block uses.
-    BB.replaceAllUsesWith(NewBB);
-    // Move intrinsictions to NewBB.
-    NewBB->getInstList().splice(NewBB->begin(), BB.getInstList());
-  }
+  // Splice the body of the old function right into the new function.
+  flatF->getBasicBlockList().splice(flatF->begin(), F->getBasicBlockList());
+
   // Update Block uses.
-  for (BasicBlock &BB : blockList) {
-    BasicBlock *NewBB = cast<BasicBlock>(VMap[&BB]);
-    if (updateRetType) {
-      // Replace ret with ret void.
-      if (ReturnInst *RI = dyn_cast<ReturnInst>(NewBB->getTerminator())) {
-        // Create store for return.
-        IRBuilder<> Builder(RI);
-        Builder.CreateRetVoid();
-        RI->eraseFromParent();
+  if (updateRetType) {
+    for (BasicBlock &BB : flatF->getBasicBlockList()) {
+      if (updateRetType) {
+        // Replace ret with ret void.
+        if (ReturnInst *RI = dyn_cast<ReturnInst>(BB.getTerminator())) {
+          // Create store for return.
+          IRBuilder<> Builder(RI);
+          Builder.CreateRetVoid();
+          RI->eraseFromParent();
+        }
       }
     }
   }
-
-  // Cleanup the original function.
-  F->getBasicBlockList().clear();  
 }
 
 static void SplitArrayCopy(Value *V) {

+ 1 - 1
tools/clang/test/CodeGenHLSL/recursive.hlsl

@@ -1,7 +1,7 @@
 // RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
 
 // CHECK: Recursion is not permitted
-// CHECK: Function call on user defined function
+// CHECK: with parameter is not permitted
 
 void test_inout(inout float4 m, float4 a) 
 {

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

@@ -72,7 +72,7 @@ public:
   TEST_METHOD(DisassemblyWhenInvalidThenFails)
   TEST_METHOD(DisassemblyWhenValidThenOK)
   TEST_METHOD(ValidateFromLL_Abs2)
-
+  TEST_METHOD(DxilContainerUnitTest)
 
   TEST_METHOD(ReflectionMatchesDXBC_CheckIn)
   BEGIN_TEST_METHOD(ReflectionMatchesDXBC_Full)
@@ -773,3 +773,51 @@ TEST_F(DxilContainerTest, ReflectionMatchesDXBC_Full) {
 TEST_F(DxilContainerTest, ValidateFromLL_Abs2) {
   CodeGenTestCheck(L"abs2_m.ll");
 }
+
+TEST_F(DxilContainerTest, DxilContainerUnitTest) {
+  CComPtr<IDxcCompiler> pCompiler;
+  CComPtr<IDxcBlobEncoding> pSource;
+  CComPtr<IDxcBlob> pProgram;
+  CComPtr<IDxcBlobEncoding> pDisassembly;
+  CComPtr<IDxcOperationResult> pResult;
+  std::vector<LPCWSTR> arguments;
+  arguments.emplace_back(L"/Zi");
+  
+  VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
+  CreateBlobFromText("float4 main() : SV_Target { return 0; }", &pSource);
+  // Test DxilContainer with ShaderDebugInfoDXIL
+  VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main", L"ps_6_0", arguments.data(), 1, nullptr, 0, nullptr, &pResult));
+  VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
+  
+  const hlsl::DxilContainerHeader *pHeader = static_cast<const hlsl::DxilContainerHeader *> (pProgram->GetBufferPointer());
+  VERIFY_IS_TRUE(hlsl::IsValidDxilContainer(pHeader, pProgram->GetBufferSize()));
+  VERIFY_IS_NOT_NULL(hlsl::IsDxilContainerLike(pHeader, pProgram->GetBufferSize()));
+  VERIFY_IS_NOT_NULL(hlsl::GetDxilProgramHeader(pHeader, hlsl::DxilFourCC::DFCC_DXIL));
+  VERIFY_IS_NOT_NULL(hlsl::GetDxilProgramHeader(pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
+  VERIFY_IS_NOT_NULL(hlsl::GetDxilPartByType(pHeader, hlsl::DxilFourCC::DFCC_DXIL));
+  VERIFY_IS_NOT_NULL(hlsl::GetDxilPartByType(pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
+  
+  pResult.Release();
+  pProgram.Release();
+
+  // Test DxilContainer without ShaderDebugInfoDXIL
+  VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main", L"ps_6_0", nullptr, 0, nullptr, 0, nullptr, &pResult));
+  VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
+  
+  pHeader = static_cast<const hlsl::DxilContainerHeader *> (pProgram->GetBufferPointer());
+  VERIFY_IS_TRUE(hlsl::IsValidDxilContainer(pHeader, pProgram->GetBufferSize()));
+  VERIFY_IS_NOT_NULL(hlsl::IsDxilContainerLike(pHeader, pProgram->GetBufferSize()));
+  VERIFY_IS_NOT_NULL(hlsl::GetDxilProgramHeader(pHeader, hlsl::DxilFourCC::DFCC_DXIL));
+  VERIFY_IS_NULL(hlsl::GetDxilProgramHeader(pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
+  VERIFY_IS_NOT_NULL(hlsl::GetDxilPartByType(pHeader, hlsl::DxilFourCC::DFCC_DXIL));
+  VERIFY_IS_NULL(hlsl::GetDxilPartByType(pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
+
+  // Test Empty DxilContainer
+  hlsl::DxilContainerHeader header;
+  SetupBasicHeader(&header);
+  VERIFY_IS_TRUE(hlsl::IsValidDxilContainer(&header, header.ContainerSizeInBytes));
+  VERIFY_IS_NOT_NULL(hlsl::IsDxilContainerLike(&header, header.ContainerSizeInBytes));
+  VERIFY_IS_NULL(hlsl::GetDxilProgramHeader(&header, hlsl::DxilFourCC::DFCC_DXIL));
+  VERIFY_IS_NULL(hlsl::GetDxilPartByType(&header, hlsl::DxilFourCC::DFCC_DXIL));
+
+}

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

@@ -455,7 +455,7 @@ TEST_F(ExtensionTest, IntrinsicWhenAvailableThenUsed) {
   // - second argument is float, ie it got scalarized
   VERIFY_IS_TRUE(
     disassembly.npos !=
-    disassembly.find("call void @\"test.\\01?test_proc@hlsl@@YAXV?$vector@M$01@@@Z.r\"(i32 2, float %6)"));
+    disassembly.find("call void @\"test.\\01?test_proc@hlsl@@YAXV?$vector@M$01@@@Z.r\"(i32 2, float"));
   VERIFY_IS_TRUE(
     disassembly.npos !=
     disassembly.find("call float @\"test.\\01?test_fn@hlsl@@YA?AV?$vector@M$01@@V2@@Z.r\"(i32 1, float"));

+ 81 - 62
tools/clang/unittests/HLSL/ValidationTest.cpp

@@ -15,6 +15,7 @@
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Regex.h"
+#include "llvm/ADT/ArrayRef.h"
 
 #include <atlbase.h>
 
@@ -120,6 +121,7 @@ public:
   TEST_METHOD(MinPrecisionBitCast)
   TEST_METHOD(StructBitCast)
   TEST_METHOD(MultiDimArray)
+  TEST_METHOD(NoFunctionParam)
 
   TEST_METHOD(ClipCullMaxComponents)
   TEST_METHOD(ClipCullMaxRows)
@@ -286,7 +288,7 @@ public:
   }
 
   void RewriteAssemblyCheckMsg(LPCSTR pSource, LPCSTR pShaderModel,
-                               LPCSTR pLookFor, LPCSTR pReplacement,
+                               llvm::ArrayRef<LPCSTR> pLookFors, llvm::ArrayRef<LPCSTR> pReplacements,
                                LPCSTR pErrorMsg, bool bRegex = false) {
     CComPtr<IDxcBlob> pText;
     CComPtr<IDxcBlobEncoding> pSourceBlob;
@@ -297,7 +299,7 @@ public:
 
     Utf8ToBlob(m_dllSupport, pSource, &pSourceBlob);
 
-    RewriteAssemblyToText(pSourceBlob, pShaderModel, pLookFor, pReplacement, &pText, bRegex);
+    RewriteAssemblyToText(pSourceBlob, pShaderModel, pLookFors, pReplacements, &pText, bRegex);
 
     CComPtr<IDxcAssembler> pAssembler;
     CComPtr<IDxcOperationResult> pAssembleResult;
@@ -314,42 +316,46 @@ public:
   }
 
   void RewriteAssemblyToText(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
-                             LPCSTR pLookFor, LPCSTR pReplacement,
+                             llvm::ArrayRef<LPCSTR> pLookFors, llvm::ArrayRef<LPCSTR> pReplacements,
                              IDxcBlob **pBlob, bool bRegex = false) {
     CComPtr<IDxcBlob> pProgram;
     std::string disassembly;
     CompileSource(pSource, pShaderModel, &pProgram);
     DisassembleProgram(pProgram, &disassembly);
-    if (pLookFor && *pLookFor) {
-      if (bRegex) {
-        llvm::Regex RE(pLookFor);
-        std::string reErrors;
-        VERIFY_IS_TRUE(RE.isValid(reErrors));
-        std::string replaced = RE.sub(pReplacement, disassembly, &reErrors);
-        VERIFY_ARE_NOT_EQUAL(disassembly, replaced);
-        VERIFY_IS_TRUE(reErrors.empty());
-        disassembly = std::move(replaced);
-      } else {
-        bool found = false;
-        size_t pos = 0;
-        size_t lookForLen = strlen(pLookFor);
-        size_t replaceLen = strlen(pReplacement);
-        for (;;) {
-          pos = disassembly.find(pLookFor, pos);
-          if (pos == std::string::npos)
-            break;
-          found = true; // at least once
-          disassembly.replace(pos, lookForLen, pReplacement);
-          pos += replaceLen;
+    for (unsigned i = 0; i < pLookFors.size(); ++i) {
+      LPCSTR pLookFor = pLookFors[i];
+      LPCSTR pReplacement = pReplacements[i];
+      if (pLookFor && *pLookFor) {
+        if (bRegex) {
+          llvm::Regex RE(pLookFor);
+          std::string reErrors;
+          VERIFY_IS_TRUE(RE.isValid(reErrors));
+          std::string replaced = RE.sub(pReplacement, disassembly, &reErrors);
+          VERIFY_ARE_NOT_EQUAL(disassembly, replaced);
+          VERIFY_IS_TRUE(reErrors.empty());
+          disassembly = std::move(replaced);
+        } else {
+          bool found = false;
+          size_t pos = 0;
+          size_t lookForLen = strlen(pLookFor);
+          size_t replaceLen = strlen(pReplacement);
+          for (;;) {
+            pos = disassembly.find(pLookFor, pos);
+            if (pos == std::string::npos)
+              break;
+            found = true; // at least once
+            disassembly.replace(pos, lookForLen, pReplacement);
+            pos += replaceLen;
+          }
+          VERIFY_IS_TRUE(found);
         }
-        VERIFY_IS_TRUE(found);
       }
     }
     Utf8ToBlob(m_dllSupport, disassembly.c_str(), pBlob);
   }
   
   void RewriteAssemblyCheckMsg(LPCWSTR name, LPCSTR pShaderModel,
-                               LPCSTR pLookFor, LPCSTR pReplacement,
+                               llvm::ArrayRef<LPCSTR> pLookFors, llvm::ArrayRef<LPCSTR> pReplacements,
                                LPCSTR pErrorMsg, bool bRegex = false) {
     std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(name);
     CComPtr<IDxcLibrary> pLibrary;
@@ -363,7 +369,7 @@ public:
 
     CComPtr<IDxcBlob> pText;
 
-    RewriteAssemblyToText(pSource, pShaderModel, pLookFor, pReplacement, &pText, bRegex);
+    RewriteAssemblyToText(pSource, pShaderModel, pLookFors, pReplacements, &pText, bRegex);
 
     CComPtr<IDxcAssembler> pAssembler;
     CComPtr<IDxcOperationResult> pAssembleResult;
@@ -558,7 +564,8 @@ TEST_F(ValidationTest, WhenIncorrectPSThenFail) {
 
 TEST_F(ValidationTest, WhenSmUnknownThenFail) {
   RewriteAssemblyCheckMsg("float4 main() : SV_Target { return 1; }", "ps_6_0",
-                          "{!\"ps\", i32 6, i32 0}", "{!\"ps\", i32 1, i32 2}",
+                          {"{!\"ps\", i32 6, i32 0}"},
+                          {"{!\"ps\", i32 1, i32 2}"},
                           "Unknown shader model 'ps_1_2'");
 }
 
@@ -871,15 +878,16 @@ TEST_F(ValidationTest, ArrayOfSVTarget) {
 TEST_F(ValidationTest, InfiniteLog) {
     RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
-      "op.unary.f32(i32 23, float %3)",
+      "op.unary.f32\\(i32 23, float %[0-9+]\\)",
       "op.unary.f32(i32 23, float 0x7FF0000000000000)",
-      "No indefinite logarithm");
+      "No indefinite logarithm",
+      /*bRegex*/true);
 }
 
 TEST_F(ValidationTest, InfiniteAsin) {
     RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
-      "op.unary.f32(i32 16, float %3)",
+      "op.unary.f32(i32 16, float %1)",
       "op.unary.f32(i32 16, float 0x7FF0000000000000)",
       "No indefinite arcsine");
 }
@@ -887,7 +895,7 @@ TEST_F(ValidationTest, InfiniteAsin) {
 TEST_F(ValidationTest, InfiniteAcos) {
     RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
-      "op.unary.f32(i32 15, float %3)",
+      "op.unary.f32(i32 15, float %1)",
       "op.unary.f32(i32 15, float 0x7FF0000000000000)",
       "No indefinite arccosine");
 }
@@ -895,24 +903,25 @@ TEST_F(ValidationTest, InfiniteAcos) {
 TEST_F(ValidationTest, InfiniteDdxDdy) {
     RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
-      "op.unary.f32(i32 85, float %3)",
+      "op.unary.f32\\(i32 85, float %[0-9]+\\)",
       "op.unary.f32(i32 85, float 0x7FF0000000000000)",
-      "No indefinite derivative calculation");
+      "No indefinite derivative calculation",
+      /*bRegex*/true);
 }
 
 TEST_F(ValidationTest, IDivByZero) {
     RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
-      "sdiv i32 %8, %9",
-      "sdiv i32 %8, 0",
+      "sdiv i32 %6, %7",
+      "sdiv i32 %6, 0",
       "No signed integer division by zero");
 }
 
 TEST_F(ValidationTest, UDivByZero) {
     RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
-      "udiv i32 %5, %6",
-      "udiv i32 %5, 0",
+      "udiv i32 %3, %4",
+      "udiv i32 %3, 0",
       "No unsigned integer division by zero");
 }
 
@@ -925,59 +934,66 @@ TEST_F(ValidationTest, UnusedMetadata) {
 
 TEST_F(ValidationTest, MemoryOutOfBound) {
   RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\targetArray.hlsl", "ps_6_0",
-                          "getelementptr [4 x float], [4 x float]* %12, i32 0, i32 3",
-                          "getelementptr [4 x float], [4 x float]* %12, i32 0, i32 10",
+                          "getelementptr [4 x float], [4 x float]* %7, i32 0, i32 3",
+                          "getelementptr [4 x float], [4 x float]* %7, i32 0, i32 10",
                           "Access to out-of-bounds memory is disallowed");
 }
 
 TEST_F(ValidationTest, AddrSpaceCast) {
   RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_6_0",
-                          "%12 = getelementptr [4 x float], [4 x float]* %1, i32 0, i32 0\n"
-                          "  store float %11, float* %12, align 4",
-                          "%12 = getelementptr [4 x float], [4 x float]* %1, i32 0, i32 0\n"
-                          "  %X = addrspacecast float* %12 to float addrspace(1)*    \n"
-                          "  store float %11, float addrspace(1)* %X, align 4",
+                          "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
+                          "  store float %10, float* %11, align 4",
+                          "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
+                          "  %X = addrspacecast float* %11 to float addrspace(1)*    \n"
+                          "  store float %10, float addrspace(1)* %X, align 4",
                           "generic address space");
 }
 
 TEST_F(ValidationTest, PtrBitCast) {
   RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_6_0",
-                          "%12 = getelementptr [4 x float], [4 x float]* %1, i32 0, i32 0\n"
-                          "  store float %11, float* %12, align 4",
-                          "%12 = getelementptr [4 x float], [4 x float]* %1, i32 0, i32 0\n"
-                          "  %X = bitcast float* %12 to double*    \n"
-                          "  store float %11, float* %12, align 4",
+                          "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
+                          "  store float %10, float* %11, align 4",
+                          "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
+                          "  %X = bitcast float* %11 to double*    \n"
+                          "  store float %10, float* %11, align 4",
                           "Pointer type bitcast must be have same size");
 }
 
 TEST_F(ValidationTest, MinPrecisionBitCast) {
   RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_6_0",
-                          "%12 = getelementptr [4 x float], [4 x float]* %1, i32 0, i32 0\n"
-                          "  store float %11, float* %12, align 4",
-                          "%12 = getelementptr [4 x float], [4 x float]* %1, i32 0, i32 0\n"
-                          "  %X = bitcast float* %12 to [2 x half]*    \n"
-                          "  store float %11, float* %12, align 4",
+                          "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
+                          "  store float %10, float* %11, align 4",
+                          "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
+                          "  %X = bitcast float* %11 to [2 x half]*    \n"
+                          "  store float %10, float* %11, align 4",
                           "Bitcast on minprecison types is not allowed");
 }
 
 TEST_F(ValidationTest, StructBitCast) {
   RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_6_0",
-                          "%12 = getelementptr [4 x float], [4 x float]* %1, i32 0, i32 0\n"
-                          "  store float %11, float* %12, align 4",
-                          "%12 = getelementptr [4 x float], [4 x float]* %1, i32 0, i32 0\n"
-                          "  %X = bitcast float* %12 to %dx.types.Handle*    \n"
-                          "  store float %11, float* %12, align 4",
+                          "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
+                          "  store float %10, float* %11, align 4",
+                          "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
+                          "  %X = bitcast float* %11 to %dx.types.Handle*    \n"
+                          "  store float %10, float* %11, align 4",
                           "Bitcast on struct types is not allowed");
 }
 
 TEST_F(ValidationTest, MultiDimArray) {
   RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_6_0",
-                          "%1 = alloca [4 x float]",
-                          "%1 = alloca [4 x float]\n"
+                          "%0 = alloca [4 x float]",
+                          "%0 = alloca [4 x float]\n"
                           "  %md = alloca [2 x [4 x float]]",
                           "Only one dimension allowed for array type");
 }
 
+TEST_F(ValidationTest, NoFunctionParam) {
+  RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\abs2.hlsl", "ps_6_0",
+                          {"define void @main()", "void ()* @main", "!5 = !{!6}"},
+                          {"define void @main(<4 x i32> %mainArg)", "void (<4 x i32>)* @main", "!5 = !{!6, !6}"},
+                          "with parameter is not permitted");
+}
+
 TEST_F(ValidationTest, WhenWaveAffectsGradientThenFail) {
   TestCheck(L"val-wave-failures-ps.hlsl");
 }
@@ -1636,9 +1652,11 @@ void main( \
     "vs_6_0",
 
     "!{i32 1, !\"Array\", i8 5, i8 0, !([0-9]+), i8 1, i32 2, i8 1, i32 1, i8 0, null}\n"
+    "!17 = !{i32 0, i32 1}\n"
     "!([0-9]+) = !{i32 2, !\"Value\", i8 5, i8 0, !([0-9]+), i8 1, i32 1, i8 3, i32 1, i8 1, null}",
 
     "!{i32 1, !\"Array\", i8 5, i8 0, !\\1, i8 1, i32 2, i8 1, i32 1, i8 1, null}\n"
+    "!17 = !{i32 0, i32 1}\n"
     "!\\2 = !{i32 2, !\"Value\", i8 5, i8 0, !\\3, i8 1, i32 1, i8 3, i32 2, i8 0, null}",
 
     "signature element Value at location \\(2,0\\) size \\(1,3\\) overlaps another signature element.",
@@ -1653,6 +1671,7 @@ float4 main(float4 f4 : Input, out float d0 : SV_Depth, out float d1 : SV_Target
     "ps_6_0",
 
     "!{i32 1, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 1, i32 1, i8 0, null}\n"
+    "!16 = !{i32 1}\n"
     "!([0-9]+) = !{i32 2, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 4, i32 0, i8 0, null}",
 
     "!{i32 1, !\"SV_DepthGreaterEqual\", i8 9, i8 19, !\\3, i8 0, i32 1, i8 1, i32 -1, i8 -1, null}\n"

+ 1 - 1
utils/hct/hctdb.py

@@ -1635,7 +1635,7 @@ class db_dxil(object):
         self.add_valrule("Flow.Reducible", "Execution flow must be reducible")
         self.add_valrule("Flow.NoRecusion", "Recursion is not permitted")
         self.add_valrule("Flow.DeadLoop", "Loop must have break")
-        self.add_valrule_msg("Flow.FunctionCall", "Function call on user defined function with parameter is not permitted", "Function call on user defined function with parameter %0 is not permitted, it should be inlined")
+        self.add_valrule_msg("Flow.FunctionCall", "Function with parameter is not permitted", "Function %0 with parameter is not permitted, it should be inlined")
 
         self.add_valrule_msg("Decl.DxilNsReserved", "The DXIL reserved prefixes must only be used by built-in functions and types", "Declaration '%0' uses a reserved prefix")
         self.add_valrule_msg("Decl.DxilFnExtern", "External function must be a DXIL function", "External function '%0' is not a DXIL function")