Просмотр исходного кода

Fixed issues that change codegen when there's debug info. (#2190)

Adam Yang 6 лет назад
Родитель
Сommit
f240070cf1

+ 5 - 0
include/llvm/IR/LLVMContext.h

@@ -67,6 +67,11 @@ public:
   /// This ID is uniqued across modules in the current LLVMContext.
   /// This ID is uniqued across modules in the current LLVMContext.
   unsigned getMDKindID(StringRef Name) const;
   unsigned getMDKindID(StringRef Name) const;
 
 
+  // HLSL Change - Begin
+  /// Return a unique non-zero ID for the specified metadata kind if it exists.
+  bool findMDKindID(StringRef Name, unsigned *ID) const;
+  // HLSL Change - End
+
   /// getMDKindNames - Populate client supplied SmallVector with the name for
   /// getMDKindNames - Populate client supplied SmallVector with the name for
   /// custom metadata IDs registered in this LLVMContext.
   /// custom metadata IDs registered in this LLVMContext.
   void getMDKindNames(SmallVectorImpl<StringRef> &Result) const;
   void getMDKindNames(SmallVectorImpl<StringRef> &Result) const;

+ 7 - 0
lib/Analysis/MemoryDependenceAnalysis.cpp

@@ -201,6 +201,13 @@ getCallSiteDependencyFrom(CallSite CS, bool isReadOnlyCall,
 
 
   // Walk backwards through the block, looking for dependencies
   // Walk backwards through the block, looking for dependencies
   while (ScanIt != BB->begin()) {
   while (ScanIt != BB->begin()) {
+    // HLSL Change - Begin
+    // Skip debug info
+    if (isa<DbgInfoIntrinsic>(*std::prev(ScanIt))) {
+      ScanIt--; continue;
+    }
+    // HLSL Change - End
+
     // Limit the amount of scanning we do so we don't end up with quadratic
     // Limit the amount of scanning we do so we don't end up with quadratic
     // running time on extreme testcases.
     // running time on extreme testcases.
     --Limit;
     --Limit;

+ 16 - 0
lib/DXIL/DxilModule.cpp

@@ -1518,6 +1518,22 @@ void DxilModule::StripDebugRelatedCode() {
           m_pModule->getNamedMetadata(DxilMDHelper::kDxilSourceArgsMDName)) {
           m_pModule->getNamedMetadata(DxilMDHelper::kDxilSourceArgsMDName)) {
     arguments->eraseFromParent();
     arguments->eraseFromParent();
   }
   }
+
+  if (NamedMDNode *flags = m_pModule->getModuleFlagsMetadata()) {
+    SmallVector<llvm::Module::ModuleFlagEntry, 4> flagEntries;
+    m_pModule->getModuleFlagsMetadata(flagEntries);
+    flags->eraseFromParent();
+
+    for (unsigned i = 0; i < flagEntries.size(); i++) {
+      llvm::Module::ModuleFlagEntry &entry = flagEntries[i];
+      if (entry.Key->getString() == "Dwarf Version" || entry.Key->getString() == "Debug Info Version") {
+        continue;
+      }
+      m_pModule->addModuleFlag(
+        entry.Behavior, entry.Key->getString(),
+        cast<ConstantAsMetadata>(entry.Val)->getValue());
+    }
+  }
 }
 }
 DebugInfoFinder &DxilModule::GetOrCreateDebugInfoFinder() {
 DebugInfoFinder &DxilModule::GetOrCreateDebugInfoFinder() {
   if (m_pDebugInfoFinder == nullptr) {
   if (m_pDebugInfoFinder == nullptr) {

+ 1 - 1
lib/DxilContainer/DxilContainerAssembler.cpp

@@ -1596,7 +1596,7 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
     pProgramStream.Release();
     pProgramStream.Release();
     IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pProgramStream));
     IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pProgramStream));
     raw_stream_ostream outStream(pProgramStream.p);
     raw_stream_ostream outStream(pProgramStream.p);
-    WriteBitcodeToFile(pModule->GetModule(), outStream, true);
+    WriteBitcodeToFile(pModule->GetModule(), outStream, false);
   }
   }
 
 
   // Serialize debug name if requested.
   // Serialize debug name if requested.

+ 0 - 2
lib/HLSL/DxilCondenseResources.cpp

@@ -1726,8 +1726,6 @@ void DxilLowerCreateHandleForLib::UpdateResourceSymbols() {
       GV->removeDeadConstantUsers();
       GV->removeDeadConstantUsers();
       DXASSERT(GV->user_empty(), "else resource not lowered");
       DXASSERT(GV->user_empty(), "else resource not lowered");
       res->SetGlobalSymbol(UndefValue::get(GV->getType()));
       res->SetGlobalSymbol(UndefValue::get(GV->getType()));
-      if (m_HasDbgInfo)
-        LLVMUsed.emplace_back(GV);
     }
     }
   };
   };
 
 

+ 12 - 0
lib/IR/LLVMContext.cpp

@@ -252,6 +252,18 @@ void LLVMContext::emitError(unsigned LocCookie, const Twine &ErrorStr) {
 // Metadata Kind Uniquing
 // Metadata Kind Uniquing
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 
 
+// HLSL Change - Begin
+/// Return a unique non-zero ID for the specified metadata kind if it exists.
+bool LLVMContext::findMDKindID(StringRef Name, unsigned *ID) const {
+  auto it = pImpl->CustomMDKindNames.find(Name);
+  if (it != pImpl->CustomMDKindNames.end()) {
+    *ID = it->second;
+    return true;
+  }
+  return false;
+}
+// HLSL Change - End
+
 /// Return a unique non-zero ID for the specified metadata kind.
 /// Return a unique non-zero ID for the specified metadata kind.
 unsigned LLVMContext::getMDKindID(StringRef Name) const {
 unsigned LLVMContext::getMDKindID(StringRef Name) const {
   // If this is new, assign it its ID.
   // If this is new, assign it its ID.

+ 10 - 1
lib/IR/Metadata.cpp

@@ -1058,7 +1058,16 @@ void Instruction::setMetadata(StringRef Kind, MDNode *Node) {
 }
 }
 
 
 MDNode *Instruction::getMetadataImpl(StringRef Kind) const {
 MDNode *Instruction::getMetadataImpl(StringRef Kind) const {
-  return getMetadataImpl(getContext().getMDKindID(Kind));
+  unsigned KindID = 0;
+#if 0 // HLSL Change Starts
+  return getMetadataImpl(getContext().getMDKindID(Kind))
+#else
+  // Calling special function to check for existence of string id,
+  // so it doesn't get instantiated in the context.
+  if (getContext().findMDKindID(Kind, &KindID))
+    return getMetadataImpl(KindID);
+  return nullptr;
+#endif // HLSL Change Ends
 }
 }
 
 
 void Instruction::dropUnknownMetadata(ArrayRef<unsigned> KnownIDs) {
 void Instruction::dropUnknownMetadata(ArrayRef<unsigned> KnownIDs) {

+ 7 - 1
lib/Transforms/Scalar/Scalarizer.cpp

@@ -290,7 +290,13 @@ Scatterer Scalarizer::scatter(Instruction *Point, Value *V) {
     // so that it can be used everywhere.
     // so that it can be used everywhere.
     Function *F = VArg->getParent();
     Function *F = VArg->getParent();
     BasicBlock *BB = &F->getEntryBlock();
     BasicBlock *BB = &F->getEntryBlock();
-    return Scatterer(BB, BB->begin(), V, &Scattered[V]);
+    // HLSL Change - Begin
+    // return Scatterer(BB, BB->begin(), V, &Scattered[V]);
+    auto InsertPoint = BB->begin();
+    while (InsertPoint != BB->end() && isa<DbgInfoIntrinsic>(InsertPoint))
+      InsertPoint++;
+    return Scatterer(BB, InsertPoint, V, &Scattered[V]);
+    // HLSL Change - End
   }
   }
   if (Instruction *VOp = dyn_cast<Instruction>(V)) {
   if (Instruction *VOp = dyn_cast<Instruction>(V)) {
     // Put the scattered form of an instruction directly after the
     // Put the scattered form of an instruction directly after the

+ 2 - 2
lib/Transforms/Utils/SimplifyCFG.cpp

@@ -1488,7 +1488,7 @@ static bool SpeculativelyExecuteBB(BranchInst *BI, BasicBlock *ThenBB,
                                    const TargetTransformInfo &TTI) {
                                    const TargetTransformInfo &TTI) {
   // HLSL Change Begins.
   // HLSL Change Begins.
   // Skip block with control flow hint.
   // Skip block with control flow hint.
-  if (BI->hasMetadata()) {
+  if (BI->hasMetadataOtherThanDebugLoc()) {
     return false;
     return false;
   }
   }
   // HLSL Change Ends.
   // HLSL Change Ends.
@@ -1911,7 +1911,7 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI,
   Instruction *InsertPt = DomBlock->getTerminator();
   Instruction *InsertPt = DomBlock->getTerminator();
   // HLSL Change Begins.
   // HLSL Change Begins.
   // Skip block with control flow hint.
   // Skip block with control flow hint.
-  if (InsertPt->hasMetadata()) {
+  if (InsertPt->hasMetadataOtherThanDebugLoc()) {
     return false;
     return false;
   }
   }
   // HLSL Change Ends.
   // HLSL Change Ends.

+ 74 - 0
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -281,6 +281,9 @@ public:
 
 
   // Batch directories
   // Batch directories
   TEST_METHOD(CodeGenBatch)
   TEST_METHOD(CodeGenBatch)
+  BEGIN_TEST_METHOD(CodeGenHashStability)
+      TEST_METHOD_PROPERTY(L"Priority", L"2")
+  END_TEST_METHOD()
 
 
   dxc::DxcDllSupport m_dllSupport;
   dxc::DxcDllSupport m_dllSupport;
   VersionSupportInfo m_ver;
   VersionSupportInfo m_ver;
@@ -670,6 +673,72 @@ public:
     std::string disassembleString(BlobToUtf8(pDisassembleBlob));
     std::string disassembleString(BlobToUtf8(pDisassembleBlob));
     VERIFY_ARE_NOT_EQUAL(0U, disassembleString.size());
     VERIFY_ARE_NOT_EQUAL(0U, disassembleString.size());
   }
   }
+  
+  void CodeGenTestHashFullPath(LPCWSTR fullPath) {
+    FileRunTestResult t = FileRunTestResult::RunHashTestFromFileCommands(fullPath);
+    if (t.RunResult != 0) {
+      CA2W commentWide(t.ErrorMessage.c_str(), CP_UTF8);
+      WEX::Logging::Log::Comment(commentWide);
+      WEX::Logging::Log::Error(L"Run result is not zero");
+    }
+  }
+
+  void CodeGenTestHash(LPCWSTR name, bool implicitDir) {
+    std::wstring path = name;
+    if (implicitDir) {
+      path.insert(0, L"..\\CodeGenHLSL\\");
+      path = hlsl_test::GetPathToHlslDataFile(path.c_str());
+    }
+    CodeGenTestHashFullPath(path.c_str());
+  }
+
+  void CodeGenTestCheckBatchHash(std::wstring suitePath, bool implicitDir = true) {
+    using namespace llvm;
+    using namespace WEX::TestExecution;
+
+    if (implicitDir) suitePath.insert(0, L"..\\CodeGenHLSL\\");
+
+    ::llvm::sys::fs::MSFileSystem *msfPtr;
+    VERIFY_SUCCEEDED(CreateMSFileSystemForDisk(&msfPtr));
+    std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
+    ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
+    IFTLLVM(pts.error_code());
+
+    CW2A pUtf8Filename(suitePath.c_str());
+    if (!llvm::sys::path::is_absolute(pUtf8Filename.m_psz)) {
+      suitePath = hlsl_test::GetPathToHlslDataFile(suitePath.c_str());
+    }
+
+    CW2A utf8SuitePath(suitePath.c_str());
+
+    unsigned numTestsRun = 0;
+
+    std::error_code EC;
+    llvm::SmallString<128> DirNative;
+    llvm::sys::path::native(utf8SuitePath.m_psz, DirNative);
+    for (llvm::sys::fs::recursive_directory_iterator Dir(DirNative, EC), DirEnd;
+         Dir != DirEnd && !EC; Dir.increment(EC)) {
+      // Check whether this entry has an extension typically associated with
+      // headers.
+      if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path()))
+          .Cases(".hlsl", ".ll", true).Default(false))
+        continue;
+      StringRef filename = Dir->path();
+      std::string filetag = Dir->path();
+      filetag += "<HASH>";
+
+      CA2W wRelTag(filetag.data());
+      CA2W wRelPath(filename.data());
+
+      WEX::Logging::Log::StartGroup(wRelTag);
+      CodeGenTestHash(wRelPath, /*implicitDir*/ false);
+      WEX::Logging::Log::EndGroup(wRelTag);
+
+      numTestsRun++;
+    }
+
+    VERIFY_IS_GREATER_THAN(numTestsRun, (unsigned)0, L"No test files found in batch directory.");
+  }
 
 
   void CodeGenTestCheckFullPath(LPCWSTR fullPath) {
   void CodeGenTestCheckFullPath(LPCWSTR fullPath) {
     FileRunTestResult t = FileRunTestResult::RunFromFileCommands(fullPath);
     FileRunTestResult t = FileRunTestResult::RunFromFileCommands(fullPath);
@@ -2702,6 +2771,11 @@ TEST_F(CompilerTest, DISABLED_ManualFileCheckTest) {
   }
   }
 }
 }
 
 
+
+TEST_F(CompilerTest, CodeGenHashStability) {
+  CodeGenTestCheckBatchHash(L"batch");
+}
+
 TEST_F(CompilerTest, CodeGenBatch) {
 TEST_F(CompilerTest, CodeGenBatch) {
   CodeGenTestCheckBatchDir(L"batch");
   CodeGenTestCheckBatchDir(L"batch");
 }
 }

+ 3 - 0
tools/clang/unittests/HLSL/DxcTestUtils.h

@@ -94,6 +94,7 @@ public:
   FileRunCommandPart(FileRunCommandPart&&) = default;
   FileRunCommandPart(FileRunCommandPart&&) = default;
   
   
   FileRunCommandResult Run(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior);
   FileRunCommandResult Run(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior);
+  FileRunCommandResult RunHashTests(dxc::DxcDllSupport &DllSupport);
   
   
   FileRunCommandResult ReadOptsForDxc(hlsl::options::MainArgs &argStrings, hlsl::options::DxcOpts &Opts);
   FileRunCommandResult ReadOptsForDxc(hlsl::options::MainArgs &argStrings, hlsl::options::DxcOpts &Opts);
 
 
@@ -110,6 +111,7 @@ private:
   FileRunCommandResult RunTee(const FileRunCommandResult *Prior);
   FileRunCommandResult RunTee(const FileRunCommandResult *Prior);
   FileRunCommandResult RunXFail(const FileRunCommandResult *Prior);
   FileRunCommandResult RunXFail(const FileRunCommandResult *Prior);
   FileRunCommandResult RunDxilVer(dxc::DxcDllSupport& DllSupport, const FileRunCommandResult* Prior);
   FileRunCommandResult RunDxilVer(dxc::DxcDllSupport& DllSupport, const FileRunCommandResult* Prior);
+  FileRunCommandResult RunDxcHashTest(dxc::DxcDllSupport &DllSupport);
 };
 };
 
 
 void ParseCommandParts(LPCSTR commands, LPCWSTR fileName, std::vector<FileRunCommandPart> &parts);
 void ParseCommandParts(LPCSTR commands, LPCWSTR fileName, std::vector<FileRunCommandPart> &parts);
@@ -119,6 +121,7 @@ class FileRunTestResult {
 public:
 public:
   std::string ErrorMessage;
   std::string ErrorMessage;
   int RunResult;
   int RunResult;
+  static FileRunTestResult RunHashTestFromFileCommands(LPCWSTR fileName);
   static FileRunTestResult RunFromFileCommands(LPCWSTR fileName);
   static FileRunTestResult RunFromFileCommands(LPCWSTR fileName);
   static FileRunTestResult RunFromFileCommands(LPCWSTR fileName, dxc::DxcDllSupport &dllSupport);
   static FileRunTestResult RunFromFileCommands(LPCWSTR fileName, dxc::DxcDllSupport &dllSupport);
 };
 };

+ 209 - 0
tools/clang/unittests/HLSL/FileCheckerTest.cpp

@@ -30,6 +30,7 @@
 #include "DxcTestUtils.h"
 #include "DxcTestUtils.h"
 
 
 #include "llvm/Support/raw_os_ostream.h"
 #include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Support/MD5.h"
 #include "dxc/Support/Global.h"
 #include "dxc/Support/Global.h"
 #include "dxc/Support/dxcapi.use.h"
 #include "dxc/Support/dxcapi.use.h"
 #include "dxc/Support/HLSLOptions.h"
 #include "dxc/Support/HLSLOptions.h"
@@ -82,6 +83,15 @@ static std::vector<std::string> strtok(const std::string &value, const char *del
 FileRunCommandPart::FileRunCommandPart(const std::string &command, const std::string &arguments, LPCWSTR commandFileName) :
 FileRunCommandPart::FileRunCommandPart(const std::string &command, const std::string &arguments, LPCWSTR commandFileName) :
   Command(command), Arguments(arguments), CommandFileName(commandFileName) { }
   Command(command), Arguments(arguments), CommandFileName(commandFileName) { }
 
 
+FileRunCommandResult FileRunCommandPart::RunHashTests(dxc::DxcDllSupport &DllSupport) {
+  if (0 == _stricmp(Command.c_str(), "%dxc")) {
+    return RunDxcHashTest(DllSupport);
+  }
+  else {
+    return FileRunCommandResult::Success();
+  }
+}
+
 FileRunCommandResult FileRunCommandPart::Run(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior) {
 FileRunCommandResult FileRunCommandPart::Run(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior) {
   bool isFileCheck =
   bool isFileCheck =
     0 == _stricmp(Command.c_str(), "FileCheck") ||
     0 == _stricmp(Command.c_str(), "FileCheck") ||
@@ -186,6 +196,172 @@ FileRunCommandResult FileRunCommandPart::ReadOptsForDxc(
   return FileRunCommandResult::Success("");
   return FileRunCommandResult::Success("");
 }
 }
 
 
+static HRESULT ReAssembleTo(dxc::DxcDllSupport &DllSupport, void *bitcode, UINT32 size, IDxcBlob **pBlob) {
+  CComPtr<IDxcAssembler> pAssembler;
+  CComPtr<IDxcLibrary> pLibrary;
+  IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
+  IFT(DllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
+
+  CComPtr<IDxcBlobEncoding> pInBlob;
+
+  IFT(pLibrary->CreateBlobWithEncodingFromPinned(bitcode, size, 0, &pInBlob));
+  
+  CComPtr<IDxcOperationResult> pResult;
+  pAssembler->AssembleToContainer(pInBlob, &pResult);
+
+  HRESULT Result = 0;
+  IFT(pResult->GetStatus(&Result));
+  IFT(Result);
+
+  IFT(pResult->GetResult(pBlob));
+
+  return S_OK;
+}
+
+static HRESULT GetDxilBitcode(dxc::DxcDllSupport &DllSupport, IDxcBlob *pCompiledBlob, IDxcBlob **pBitcodeBlob) {
+  CComPtr<IDxcContainerReflection> pReflection;
+  CComPtr<IDxcLibrary> pLibrary;
+  IFT(DllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
+  IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
+
+  IFT(pReflection->Load(pCompiledBlob));
+
+  UINT32 uIndex = 0;
+  IFT(pReflection->FindFirstPartKind(hlsl::DFCC_DXIL, &uIndex));
+  CComPtr<IDxcBlob> pPart;
+  IFT(pReflection->GetPartContent(uIndex, &pPart));
+
+  auto header = (hlsl::DxilProgramHeader*)pPart->GetBufferPointer();
+  void *bitcode = (char *)&header->BitcodeHeader + header->BitcodeHeader.BitcodeOffset;
+  UINT32 bitcode_size = header->BitcodeHeader.BitcodeSize;
+
+  CComPtr<IDxcBlobEncoding> pBlob;
+  IFT(pLibrary->CreateBlobWithEncodingFromPinned(bitcode, bitcode_size, 0, &pBlob));
+  *pBitcodeBlob = pBlob.Detach();
+
+  return S_OK;
+}
+
+static HRESULT CompileForHash(hlsl::options::DxcOpts &opts, LPCWSTR CommandFileName, dxc::DxcDllSupport &DllSupport, std::vector<LPCWSTR> &flags, llvm::SmallString<32> &Hash, std::string &output) {
+  CComPtr<IDxcLibrary> pLibrary;
+  CComPtr<IDxcCompiler> pCompiler;
+  CComPtr<IDxcOperationResult> pResult;
+  CComPtr<IDxcBlobEncoding> pSource;
+  CComPtr<IDxcBlob> pCompiledBlob;
+  CComPtr<IDxcIncludeHandler> pIncludeHandler;
+
+  std::wstring entry =
+      Unicode::UTF8ToUTF16StringOrThrow(opts.EntryPoint.str().c_str());
+  std::wstring profile =
+      Unicode::UTF8ToUTF16StringOrThrow(opts.TargetProfile.str().c_str());
+
+  IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
+  IFT(pLibrary->CreateBlobFromFile(CommandFileName, nullptr, &pSource));
+  IFT(pLibrary->CreateIncludeHandler(&pIncludeHandler));
+  IFT(DllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
+  IFT(pCompiler->Compile(pSource, CommandFileName, entry.c_str(), profile.c_str(),
+    flags.data(), flags.size(), nullptr, 0, pIncludeHandler, &pResult));
+
+  HRESULT resultStatus = 0;
+  IFT(pResult->GetStatus(&resultStatus));
+  if (SUCCEEDED(resultStatus)) {
+
+    IFT(pResult->GetResult(&pCompiledBlob));
+
+    CComPtr<IDxcContainerReflection> pReflection;
+    IFT(DllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
+
+    // If failed to load here, it's likely some non-compile operation thing. Just fail the hash generation.
+    if (FAILED(pReflection->Load(pCompiledBlob)))
+      return E_FAIL;
+
+    CComPtr<IDxcBlob> pBitcodeBlob;
+    IFT(GetDxilBitcode(DllSupport, pCompiledBlob, &pBitcodeBlob));
+
+    CComPtr<IDxcBlob> pReassembledBlob;
+    IFT(ReAssembleTo(DllSupport, pBitcodeBlob->GetBufferPointer(), pBitcodeBlob->GetBufferSize(), &pReassembledBlob));
+
+    CComPtr<IDxcBlobEncoding> pDisassembly;
+    IFT(pCompiler->Disassemble(pReassembledBlob, &pDisassembly));
+    output = BlobToUtf8(pDisassembly);
+
+    // For now, just has the disassembly. Once we fix the bitcode differences, we'll switch to that.
+    llvm::ArrayRef<uint8_t> Data((uint8_t *)pDisassembly->GetBufferPointer(), pDisassembly->GetBufferSize());
+    llvm::MD5 md5;
+    llvm::MD5::MD5Result md5Result;
+    md5.update(Data);
+    md5.final(md5Result);
+    md5.stringifyResult(md5Result, Hash);
+
+    return S_OK;
+  }
+  else {
+    CComPtr<IDxcBlobEncoding> pErrors;
+    IFT(pResult->GetErrorBuffer(&pErrors));
+    const char *errors = (char *)pErrors->GetBufferPointer();
+    output = errors;
+    return resultStatus;
+  }
+}
+
+FileRunCommandResult FileRunCommandPart::RunDxcHashTest(dxc::DxcDllSupport &DllSupport) {
+  hlsl::options::MainArgs args;
+  hlsl::options::DxcOpts opts;
+  ReadOptsForDxc(args, opts);
+
+  std::vector<std::wstring> argWStrings;
+  CopyArgsToWStrings(opts.Args, hlsl::options::CoreOption, argWStrings);
+
+  // Extract the vanilla flags for the test (i.e. no debug or ast-dump)
+  std::vector<LPCWSTR> original_flags;
+  for (const std::wstring &a : argWStrings) {
+    if (a.find(L"ast-dump") != std::wstring::npos) continue;
+    if (a.find(L"Zi") != std::wstring::npos) continue;
+    original_flags.push_back(a.data());
+  }
+
+  std::string originalOutput;
+  llvm::SmallString<32> originalHash;
+  // If failed the original compilation, just pass the test. The original test was likely
+  // testing for failure.
+  if (FAILED(CompileForHash(opts, CommandFileName, DllSupport, original_flags, originalHash, originalOutput)))
+    return FileRunCommandResult::Success();
+
+  // Results of our compilations
+  llvm::SmallString<32> Hash1;
+  std::string Output0;
+  llvm::SmallString<32> Hash0;
+  std::string Output1;
+
+  // Fail if -Qstrip_reflect failed the compilation
+  std::vector<LPCWSTR> normal_flags = original_flags;
+  normal_flags.push_back(L"-Qstrip_reflect");
+  std::string StdErr;
+  if (FAILED(CompileForHash(opts, CommandFileName, DllSupport, normal_flags, Hash0, Output0))) {
+    StdErr += "Adding Qstrip_reflect failed compilation.";
+    StdErr += originalOutput;
+    StdErr += Output0;
+    return FileRunCommandResult::Error(StdErr);
+  }
+
+  // Fail if -Qstrip_reflect failed the compilation
+  std::vector<LPCWSTR> dbg_flags = original_flags;
+  dbg_flags.push_back(L"/Zi");
+  dbg_flags.push_back(L"-Qstrip_reflect");
+  if (FAILED(CompileForHash(opts, CommandFileName, DllSupport, dbg_flags, Hash1, Output1))) {
+    return FileRunCommandResult::Error("Adding Qstrip_reflect and Zi failed compilation.");
+  }
+
+  if (Hash0 != Hash1) {
+    StdErr = "Hashes do not match between normal and debug!!!\n";
+    StdErr += Output0;
+    StdErr += Output1;
+    return FileRunCommandResult::Error(StdErr);
+  }
+
+  return FileRunCommandResult::Success();
+}
+
 FileRunCommandResult FileRunCommandPart::RunDxc(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior) {
 FileRunCommandResult FileRunCommandPart::RunDxc(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior) {
   // Support piping stdin from prior if needed.
   // Support piping stdin from prior if needed.
   UNREFERENCED_PARAMETER(Prior);
   UNREFERENCED_PARAMETER(Prior);
@@ -498,6 +674,25 @@ FileRunCommandResult FileRunCommandPart::RunDxilVer(dxc::DxcDllSupport& DllSuppo
 class FileRunTestResultImpl : public FileRunTestResult {
 class FileRunTestResultImpl : public FileRunTestResult {
   dxc::DxcDllSupport &m_support;
   dxc::DxcDllSupport &m_support;
 
 
+  void RunHashTestFromCommands(LPCSTR commands, LPCWSTR fileName) {
+    std::vector<FileRunCommandPart> parts;
+    ParseCommandParts(commands, fileName, parts);
+    FileRunCommandResult result;
+    bool ran = false;
+    for (FileRunCommandPart & part : parts) {
+      result = part.RunHashTests(m_support);
+      ran = true;
+      break;
+    }
+    if (ran) {
+      this->RunResult = result.ExitCode;
+      this->ErrorMessage = result.StdErr;
+    }
+    else {
+      this->RunResult = 0;
+    }
+  }
+
   void RunFileCheckFromCommands(LPCSTR commands, LPCWSTR fileName) {
   void RunFileCheckFromCommands(LPCSTR commands, LPCWSTR fileName) {
     std::vector<FileRunCommandPart> parts;
     std::vector<FileRunCommandPart> parts;
     ParseCommandParts(commands, fileName, parts);
     ParseCommandParts(commands, fileName, parts);
@@ -527,8 +722,22 @@ public:
     std::string commands(GetFirstLine(fileName));
     std::string commands(GetFirstLine(fileName));
     return RunFileCheckFromCommands(commands.c_str(), fileName);
     return RunFileCheckFromCommands(commands.c_str(), fileName);
   }
   }
+
+  void RunHashTestFromFileCommands(LPCWSTR fileName) {
+    // Assume UTF-8 files.
+    std::string commands(GetFirstLine(fileName));
+    return RunHashTestFromCommands(commands.c_str(), fileName);
+  }
 };
 };
 
 
+FileRunTestResult FileRunTestResult::RunHashTestFromFileCommands(LPCWSTR fileName) {
+  dxc::DxcDllSupport dllSupport;
+  IFT(dllSupport.Initialize());
+  FileRunTestResultImpl result(dllSupport);
+  result.RunHashTestFromFileCommands(fileName);
+  return result;
+}
+
 FileRunTestResult FileRunTestResult::RunFromFileCommands(LPCWSTR fileName) {
 FileRunTestResult FileRunTestResult::RunFromFileCommands(LPCWSTR fileName) {
   dxc::DxcDllSupport dllSupport;
   dxc::DxcDllSupport dllSupport;
   IFT(dllSupport.Initialize());
   IFT(dllSupport.Initialize());