[NFC] Move DxilValidation to a dedicated folder. (#6849)

Move DxilValidation out of HLSL.
Also move code to validate dxil container into
DxilContainerValidation.cpp from DxilValidation.cpp.

This is a preparatory step for #6817.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Xiang Li 2024-08-13 17:33:09 -07:00 коммит произвёл GitHub
Родитель f810e92e72
Коммит 0e7591a6ee
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
17 изменённых файлов: 1408 добавлений и 1266 удалений

Просмотреть файл

@ -17,7 +17,6 @@ configure_file(
add_subdirectory(DXIL)
add_subdirectory(DxilContainer)
add_subdirectory(HLSL)
add_subdirectory(Support)
add_subdirectory(Tracing)

Просмотреть файл

@ -26,29 +26,7 @@ class DiagnosticInfo;
namespace hlsl {
#include "dxc/HLSL/DxilValidation.inc"
const char *GetValidationRuleText(ValidationRule value);
void GetValidationVersion(unsigned *pMajor, unsigned *pMinor);
HRESULT ValidateDxilModule(llvm::Module *pModule, llvm::Module *pDebugModule);
// DXIL Container Verification Functions (return false on failure)
bool VerifySignatureMatches(llvm::Module *pModule,
hlsl::DXIL::SignatureKind SigKind,
const void *pSigData, uint32_t SigSize);
// PSV = data for Pipeline State Validation
bool VerifyPSVMatches(llvm::Module *pModule, const void *pPSVData,
uint32_t PSVSize);
// PSV = data for Pipeline State Validation
bool VerifyRDATMatches(llvm::Module *pModule, const void *pRDATData,
uint32_t RDATSize);
bool VerifyFeatureInfoMatches(llvm::Module *pModule,
const void *pFeatureInfoData,
uint32_t FeatureInfoSize);
// Validate the container parts, assuming supplied module is valid, loaded from
// the container provided
@ -106,4 +84,5 @@ public:
static void PrintDiagnosticHandler(const llvm::DiagnosticInfo &DI,
void *Context);
};
} // namespace hlsl

Просмотреть файл

@ -1 +0,0 @@
add_hlsl_hctgen(DxilValidationInc OUTPUT DxilValidation.inc BUILD_DIR)

Просмотреть файл

@ -30,6 +30,7 @@ add_subdirectory(DxilPdbInfo) # HLSL Change
add_subdirectory(DxilPIXPasses) # HLSL Change
add_subdirectory(DxilDia) # HLSL Change
add_subdirectory(DxilRootSignature) # HLSL Change
add_subdirectory(DxilValidation) # HLSL Change
add_subdirectory(DxcBindingTable) # HLSL Change
add_subdirectory(DxrFallback) # HLSL Change
add_subdirectory(DxilCompression) # HLSL Change

Просмотреть файл

@ -0,0 +1,15 @@
# Copyright (C) Microsoft Corporation. All rights reserved.
# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details.
add_hlsl_hctgen(DxilValidationInc OUTPUT DxilValidation.inc BUILD_DIR)
add_hlsl_hctgen(DxilValidation OUTPUT DxilValidationImpl.inc BUILD_DIR)
add_llvm_library(LLVMDxilValidation
DxilContainerValidation.cpp
DxilValidation.cpp
DxilValidationUtils.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/IR
)
add_dependencies(LLVMDxilValidation intrinsics_gen)

Просмотреть файл

@ -0,0 +1,705 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilContainerValidation.cpp //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// This file provides support for validating DXIL container. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "dxc/Support/FileIOHelper.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/WinIncludes.h"
#include "dxc/DxilContainer/DxilContainer.h"
#include "dxc/DxilContainer/DxilContainerAssembler.h"
#include "dxc/DxilContainer/DxilPipelineStateValidation.h"
#include "dxc/DxilContainer/DxilRuntimeReflection.h"
#include "dxc/DxilRootSignature/DxilRootSignature.h"
#include "dxc/DxilValidation/DxilValidation.h"
#include "dxc/DXIL/DxilModule.h"
#include "dxc/DXIL/DxilUtil.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "DxilValidationUtils.h"
#include <memory>
using std::unique_ptr;
using std::unordered_set;
using std::vector;
namespace {
// Utility class for setting and restoring the diagnostic context so we may
// capture errors/warnings
struct DiagRestore {
LLVMContext *Ctx = nullptr;
void *OrigDiagContext;
LLVMContext::DiagnosticHandlerTy OrigHandler;
DiagRestore(llvm::LLVMContext &InputCtx, void *DiagContext) : Ctx(&InputCtx) {
init(DiagContext);
}
DiagRestore(Module *M, void *DiagContext) {
if (!M)
return;
Ctx = &M->getContext();
init(DiagContext);
}
~DiagRestore() {
if (!Ctx)
return;
Ctx->setDiagnosticHandler(OrigHandler, OrigDiagContext);
}
private:
void init(void *DiagContext) {
OrigHandler = Ctx->getDiagnosticHandler();
OrigDiagContext = Ctx->getDiagnosticContext();
Ctx->setDiagnosticHandler(
hlsl::PrintDiagnosticContext::PrintDiagnosticHandler, DiagContext);
}
};
static void emitDxilDiag(LLVMContext &Ctx, const char *str) {
hlsl::dxilutil::EmitErrorOnContext(Ctx, str);
}
} // namespace
namespace hlsl {
// DXIL Container Verification Functions
static void VerifyBlobPartMatches(ValidationContext &ValCtx, LPCSTR pName,
DxilPartWriter *pWriter, const void *pData,
uint32_t Size) {
if (!pData && pWriter->size()) {
// No blob part, but writer says non-zero size is expected.
ValCtx.EmitFormatError(ValidationRule::ContainerPartMissing, {pName});
return;
}
// Compare sizes
if (pWriter->size() != Size) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartMatches, {pName});
return;
}
if (Size == 0) {
return;
}
CComPtr<AbstractMemoryStream> pOutputStream;
IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pOutputStream));
pOutputStream->Reserve(Size);
pWriter->write(pOutputStream);
DXASSERT(pOutputStream->GetPtrSize() == Size,
"otherwise, DxilPartWriter misreported size");
if (memcmp(pData, pOutputStream->GetPtr(), Size)) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartMatches, {pName});
return;
}
return;
}
static void VerifySignatureMatches(ValidationContext &ValCtx,
DXIL::SignatureKind SigKind,
const void *pSigData, uint32_t SigSize) {
// Generate corresponding signature from module and memcmp
const char *pName = nullptr;
switch (SigKind) {
case hlsl::DXIL::SignatureKind::Input:
pName = "Program Input Signature";
break;
case hlsl::DXIL::SignatureKind::Output:
pName = "Program Output Signature";
break;
case hlsl::DXIL::SignatureKind::PatchConstOrPrim:
if (ValCtx.DxilMod.GetShaderModel()->GetKind() == DXIL::ShaderKind::Mesh)
pName = "Program Primitive Signature";
else
pName = "Program Patch Constant Signature";
break;
default:
break;
}
unique_ptr<DxilPartWriter> pWriter(
NewProgramSignatureWriter(ValCtx.DxilMod, SigKind));
VerifyBlobPartMatches(ValCtx, pName, pWriter.get(), pSigData, SigSize);
}
bool VerifySignatureMatches(llvm::Module *pModule, DXIL::SignatureKind SigKind,
const void *pSigData, uint32_t SigSize) {
ValidationContext ValCtx(*pModule, nullptr, pModule->GetOrCreateDxilModule());
VerifySignatureMatches(ValCtx, SigKind, pSigData, SigSize);
return !ValCtx.Failed;
}
static void VerifyPSVMatches(ValidationContext &ValCtx, const void *pPSVData,
uint32_t PSVSize) {
uint32_t PSVVersion =
MAX_PSV_VERSION; // This should be set to the newest version
unique_ptr<DxilPartWriter> pWriter(NewPSVWriter(ValCtx.DxilMod, PSVVersion));
// Try each version in case an earlier version matches module
while (PSVVersion && pWriter->size() != PSVSize) {
PSVVersion--;
pWriter.reset(NewPSVWriter(ValCtx.DxilMod, PSVVersion));
}
// generate PSV data from module and memcmp
VerifyBlobPartMatches(ValCtx, "Pipeline State Validation", pWriter.get(),
pPSVData, PSVSize);
}
static void VerifyFeatureInfoMatches(ValidationContext &ValCtx,
const void *pFeatureInfoData,
uint32_t FeatureInfoSize) {
// generate Feature Info data from module and memcmp
unique_ptr<DxilPartWriter> pWriter(NewFeatureInfoWriter(ValCtx.DxilMod));
VerifyBlobPartMatches(ValCtx, "Feature Info", pWriter.get(), pFeatureInfoData,
FeatureInfoSize);
}
// return true if the pBlob is a valid, well-formed CompilerVersion part, false
// otherwise
bool ValidateCompilerVersionPart(const void *pBlobPtr, UINT blobSize) {
// The hlsl::DxilCompilerVersion struct is always 16 bytes. (2 2-byte
// uint16's, 3 4-byte uint32's) The blob size should absolutely never be less
// than 16 bytes.
if (blobSize < sizeof(hlsl::DxilCompilerVersion)) {
return false;
}
const hlsl::DxilCompilerVersion *pDCV =
(const hlsl::DxilCompilerVersion *)pBlobPtr;
if (pDCV->VersionStringListSizeInBytes == 0) {
// No version strings, just make sure there is no extra space.
return blobSize == sizeof(hlsl::DxilCompilerVersion);
}
// after this point, we know VersionStringListSizeInBytes >= 1, because it is
// a UINT
UINT EndOfVersionStringIndex =
sizeof(hlsl::DxilCompilerVersion) + pDCV->VersionStringListSizeInBytes;
// Make sure that the buffer size is large enough to contain both the DCV
// struct and the version string but not any larger than necessary
if (PSVALIGN4(EndOfVersionStringIndex) != blobSize) {
return false;
}
const char *VersionStringsListData =
(const char *)pBlobPtr + sizeof(hlsl::DxilCompilerVersion);
UINT VersionStringListSizeInBytes = pDCV->VersionStringListSizeInBytes;
// now make sure that any pad bytes that were added are null-terminators.
for (UINT i = VersionStringListSizeInBytes;
i < blobSize - sizeof(hlsl::DxilCompilerVersion); i++) {
if (VersionStringsListData[i] != '\0') {
return false;
}
}
// Now, version string validation
// first, the final byte of the string should always be null-terminator so
// that the string ends
if (VersionStringsListData[VersionStringListSizeInBytes - 1] != '\0') {
return false;
}
// construct the first string
// data format for VersionString can be see in the definition for the
// DxilCompilerVersion struct. summary: 2 strings that each end with the null
// terminator, and [0-3] null terminators after the final null terminator
StringRef firstStr(VersionStringsListData);
// if the second string exists, attempt to construct it.
if (VersionStringListSizeInBytes > (firstStr.size() + 1)) {
StringRef secondStr(VersionStringsListData + firstStr.size() + 1);
// the VersionStringListSizeInBytes member should be exactly equal to the
// two string lengths, plus the 2 null terminator bytes.
if (VersionStringListSizeInBytes !=
firstStr.size() + secondStr.size() + 2) {
return false;
}
} else {
// the VersionStringListSizeInBytes member should be exactly equal to the
// first string length, plus the 1 null terminator byte.
if (VersionStringListSizeInBytes != firstStr.size() + 1) {
return false;
}
}
return true;
}
static void VerifyRDATMatches(ValidationContext &ValCtx, const void *pRDATData,
uint32_t RDATSize) {
const char *PartName = "Runtime Data (RDAT)";
RDAT::DxilRuntimeData rdat(pRDATData, RDATSize);
if (!rdat.Validate()) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartMatches, {PartName});
return;
}
// If DxilModule subobjects already loaded, validate these against the RDAT
// blob, otherwise, load subobject into DxilModule to generate reference RDAT.
if (!ValCtx.DxilMod.GetSubobjects()) {
auto table = rdat.GetSubobjectTable();
if (table && table.Count() > 0) {
ValCtx.DxilMod.ResetSubobjects(new DxilSubobjects());
if (!LoadSubobjectsFromRDAT(*ValCtx.DxilMod.GetSubobjects(), rdat)) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartMatches,
{PartName});
return;
}
}
}
unique_ptr<DxilPartWriter> pWriter(NewRDATWriter(ValCtx.DxilMod));
VerifyBlobPartMatches(ValCtx, PartName, pWriter.get(), pRDATData, RDATSize);
}
bool VerifyRDATMatches(llvm::Module *pModule, const void *pRDATData,
uint32_t RDATSize) {
ValidationContext ValCtx(*pModule, nullptr, pModule->GetOrCreateDxilModule());
VerifyRDATMatches(ValCtx, pRDATData, RDATSize);
return !ValCtx.Failed;
}
bool VerifyFeatureInfoMatches(llvm::Module *pModule,
const void *pFeatureInfoData,
uint32_t FeatureInfoSize) {
ValidationContext ValCtx(*pModule, nullptr, pModule->GetOrCreateDxilModule());
VerifyFeatureInfoMatches(ValCtx, pFeatureInfoData, FeatureInfoSize);
return !ValCtx.Failed;
}
HRESULT ValidateDxilContainerParts(llvm::Module *pModule,
llvm::Module *pDebugModule,
const DxilContainerHeader *pContainer,
uint32_t ContainerSize) {
DXASSERT_NOMSG(pModule);
if (!pContainer || !IsValidDxilContainer(pContainer, ContainerSize)) {
return DXC_E_CONTAINER_INVALID;
}
DxilModule *pDxilModule = DxilModule::TryGetDxilModule(pModule);
if (!pDxilModule) {
return DXC_E_IR_VERIFICATION_FAILED;
}
ValidationContext ValCtx(*pModule, pDebugModule, *pDxilModule);
DXIL::ShaderKind ShaderKind = pDxilModule->GetShaderModel()->GetKind();
bool bTessOrMesh = ShaderKind == DXIL::ShaderKind::Hull ||
ShaderKind == DXIL::ShaderKind::Domain ||
ShaderKind == DXIL::ShaderKind::Mesh;
std::unordered_set<uint32_t> FourCCFound;
const DxilPartHeader *pRootSignaturePart = nullptr;
const DxilPartHeader *pPSVPart = nullptr;
for (auto it = begin(pContainer), itEnd = end(pContainer); it != itEnd;
++it) {
const DxilPartHeader *pPart = *it;
char szFourCC[5];
PartKindToCharArray(pPart->PartFourCC, szFourCC);
if (FourCCFound.find(pPart->PartFourCC) != FourCCFound.end()) {
// Two parts with same FourCC found
ValCtx.EmitFormatError(ValidationRule::ContainerPartRepeated, {szFourCC});
continue;
}
FourCCFound.insert(pPart->PartFourCC);
switch (pPart->PartFourCC) {
case DFCC_InputSignature:
if (ValCtx.isLibProfile) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartInvalid,
{szFourCC});
} else {
VerifySignatureMatches(ValCtx, DXIL::SignatureKind::Input,
GetDxilPartData(pPart), pPart->PartSize);
}
break;
case DFCC_OutputSignature:
if (ValCtx.isLibProfile) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartInvalid,
{szFourCC});
} else {
VerifySignatureMatches(ValCtx, DXIL::SignatureKind::Output,
GetDxilPartData(pPart), pPart->PartSize);
}
break;
case DFCC_PatchConstantSignature:
if (ValCtx.isLibProfile) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartInvalid,
{szFourCC});
} else {
if (bTessOrMesh) {
VerifySignatureMatches(ValCtx, DXIL::SignatureKind::PatchConstOrPrim,
GetDxilPartData(pPart), pPart->PartSize);
} else {
ValCtx.EmitFormatError(ValidationRule::ContainerPartMatches,
{"Program Patch Constant Signature"});
}
}
break;
case DFCC_FeatureInfo:
VerifyFeatureInfoMatches(ValCtx, GetDxilPartData(pPart), pPart->PartSize);
break;
case DFCC_CompilerVersion:
// This blob is either a PDB, or a library profile
if (ValCtx.isLibProfile) {
if (!ValidateCompilerVersionPart((void *)GetDxilPartData(pPart),
pPart->PartSize)) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartInvalid,
{szFourCC});
}
} else {
ValCtx.EmitFormatError(ValidationRule::ContainerPartInvalid,
{szFourCC});
}
break;
case DFCC_RootSignature:
pRootSignaturePart = pPart;
if (ValCtx.isLibProfile) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartInvalid,
{szFourCC});
}
break;
case DFCC_PipelineStateValidation:
pPSVPart = pPart;
if (ValCtx.isLibProfile) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartInvalid,
{szFourCC});
} else {
VerifyPSVMatches(ValCtx, GetDxilPartData(pPart), pPart->PartSize);
}
break;
// Skip these
case DFCC_ResourceDef:
case DFCC_ShaderStatistics:
case DFCC_PrivateData:
case DFCC_DXIL:
case DFCC_ShaderDebugInfoDXIL:
case DFCC_ShaderDebugName:
continue;
case DFCC_ShaderHash:
if (pPart->PartSize != sizeof(DxilShaderHash)) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartInvalid,
{szFourCC});
}
break;
// Runtime Data (RDAT) for libraries
case DFCC_RuntimeData:
if (ValCtx.isLibProfile) {
// TODO: validate without exact binary comparison of serialized data
// - support earlier versions
// - verify no newer record versions than known here (size no larger
// than newest version)
// - verify all data makes sense and matches expectations based on
// module
VerifyRDATMatches(ValCtx, GetDxilPartData(pPart), pPart->PartSize);
} else {
ValCtx.EmitFormatError(ValidationRule::ContainerPartInvalid,
{szFourCC});
}
break;
case DFCC_Container:
default:
ValCtx.EmitFormatError(ValidationRule::ContainerPartInvalid, {szFourCC});
break;
}
}
// Verify required parts found
if (ValCtx.isLibProfile) {
if (FourCCFound.find(DFCC_RuntimeData) == FourCCFound.end()) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartMissing,
{"Runtime Data (RDAT)"});
}
} else {
if (FourCCFound.find(DFCC_InputSignature) == FourCCFound.end()) {
VerifySignatureMatches(ValCtx, DXIL::SignatureKind::Input, nullptr, 0);
}
if (FourCCFound.find(DFCC_OutputSignature) == FourCCFound.end()) {
VerifySignatureMatches(ValCtx, DXIL::SignatureKind::Output, nullptr, 0);
}
if (bTessOrMesh &&
FourCCFound.find(DFCC_PatchConstantSignature) == FourCCFound.end() &&
pDxilModule->GetPatchConstOrPrimSignature().GetElements().size()) {
ValCtx.EmitFormatError(ValidationRule::ContainerPartMissing,
{"Program Patch Constant Signature"});
}
if (FourCCFound.find(DFCC_FeatureInfo) == FourCCFound.end()) {
// Could be optional, but RS1 runtime doesn't handle this case properly.
ValCtx.EmitFormatError(ValidationRule::ContainerPartMissing,
{"Feature Info"});
}
// Validate Root Signature
if (pPSVPart) {
if (pRootSignaturePart) {
std::string diagStr;
raw_string_ostream DiagStream(diagStr);
try {
RootSignatureHandle RS;
RS.LoadSerialized(
(const uint8_t *)GetDxilPartData(pRootSignaturePart),
pRootSignaturePart->PartSize);
RS.Deserialize();
IFTBOOL(VerifyRootSignatureWithShaderPSV(
RS.GetDesc(), pDxilModule->GetShaderModel()->GetKind(),
GetDxilPartData(pPSVPart), pPSVPart->PartSize,
DiagStream),
DXC_E_INCORRECT_ROOT_SIGNATURE);
} catch (...) {
ValCtx.EmitError(ValidationRule::ContainerRootSignatureIncompatible);
emitDxilDiag(pModule->getContext(), DiagStream.str().c_str());
}
}
} else {
ValCtx.EmitFormatError(ValidationRule::ContainerPartMissing,
{"Pipeline State Validation"});
}
}
if (ValCtx.Failed) {
return DXC_E_MALFORMED_CONTAINER;
}
return S_OK;
}
static HRESULT FindDxilPart(const void *pContainerBytes, uint32_t ContainerSize,
DxilFourCC FourCC, const DxilPartHeader **ppPart) {
const DxilContainerHeader *pContainer =
IsDxilContainerLike(pContainerBytes, ContainerSize);
if (!pContainer) {
IFR(DXC_E_CONTAINER_INVALID);
}
if (!IsValidDxilContainer(pContainer, ContainerSize)) {
IFR(DXC_E_CONTAINER_INVALID);
}
DxilPartIterator it =
std::find_if(begin(pContainer), end(pContainer), DxilPartIsType(FourCC));
if (it == end(pContainer)) {
IFR(DXC_E_CONTAINER_MISSING_DXIL);
}
const DxilProgramHeader *pProgramHeader =
reinterpret_cast<const DxilProgramHeader *>(GetDxilPartData(*it));
if (!IsValidDxilProgramHeader(pProgramHeader, (*it)->PartSize)) {
IFR(DXC_E_CONTAINER_INVALID);
}
*ppPart = *it;
return S_OK;
}
HRESULT ValidateLoadModule(const char *pIL, uint32_t ILLength,
unique_ptr<llvm::Module> &pModule, LLVMContext &Ctx,
llvm::raw_ostream &DiagStream, unsigned bLazyLoad) {
llvm::DiagnosticPrinterRawOStream DiagPrinter(DiagStream);
PrintDiagnosticContext DiagContext(DiagPrinter);
DiagRestore DR(Ctx, &DiagContext);
std::unique_ptr<llvm::MemoryBuffer> pBitcodeBuf;
pBitcodeBuf.reset(llvm::MemoryBuffer::getMemBuffer(
llvm::StringRef(pIL, ILLength), "", false)
.release());
ErrorOr<std::unique_ptr<Module>> loadedModuleResult =
bLazyLoad == 0
? llvm::parseBitcodeFile(pBitcodeBuf->getMemBufferRef(), Ctx, nullptr,
true /*Track Bitstream*/)
: llvm::getLazyBitcodeModule(std::move(pBitcodeBuf), Ctx, nullptr,
false, true /*Track Bitstream*/);
// DXIL disallows some LLVM bitcode constructs, like unaccounted-for
// sub-blocks. These appear as warnings, which the validator should reject.
if (DiagContext.HasErrors() || DiagContext.HasWarnings() ||
loadedModuleResult.getError())
return DXC_E_IR_VERIFICATION_FAILED;
pModule = std::move(loadedModuleResult.get());
return S_OK;
}
HRESULT ValidateDxilBitcode(const char *pIL, uint32_t ILLength,
llvm::raw_ostream &DiagStream) {
LLVMContext Ctx;
std::unique_ptr<llvm::Module> pModule;
llvm::DiagnosticPrinterRawOStream DiagPrinter(DiagStream);
PrintDiagnosticContext DiagContext(DiagPrinter);
Ctx.setDiagnosticHandler(PrintDiagnosticContext::PrintDiagnosticHandler,
&DiagContext, true);
HRESULT hr;
if (FAILED(hr = ValidateLoadModule(pIL, ILLength, pModule, Ctx, DiagStream,
/*bLazyLoad*/ false)))
return hr;
if (FAILED(hr = ValidateDxilModule(pModule.get(), nullptr)))
return hr;
DxilModule &dxilModule = pModule->GetDxilModule();
auto &SerializedRootSig = dxilModule.GetSerializedRootSignature();
if (!SerializedRootSig.empty()) {
unique_ptr<DxilPartWriter> pWriter(NewPSVWriter(dxilModule));
DXASSERT_NOMSG(pWriter->size());
CComPtr<AbstractMemoryStream> pOutputStream;
IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pOutputStream));
pOutputStream->Reserve(pWriter->size());
pWriter->write(pOutputStream);
DxilVersionedRootSignature desc;
try {
DeserializeRootSignature(SerializedRootSig.data(),
SerializedRootSig.size(), desc.get_address_of());
if (!desc.get()) {
return DXC_E_INCORRECT_ROOT_SIGNATURE;
}
IFTBOOL(VerifyRootSignatureWithShaderPSV(
desc.get(), dxilModule.GetShaderModel()->GetKind(),
pOutputStream->GetPtr(), pWriter->size(), DiagStream),
DXC_E_INCORRECT_ROOT_SIGNATURE);
} catch (...) {
return DXC_E_INCORRECT_ROOT_SIGNATURE;
}
}
if (DiagContext.HasErrors() || DiagContext.HasWarnings()) {
return DXC_E_IR_VERIFICATION_FAILED;
}
return S_OK;
}
static HRESULT ValidateLoadModuleFromContainer(
const void *pContainer, uint32_t ContainerSize,
std::unique_ptr<llvm::Module> &pModule,
std::unique_ptr<llvm::Module> &pDebugModule, llvm::LLVMContext &Ctx,
LLVMContext &DbgCtx, llvm::raw_ostream &DiagStream, unsigned bLazyLoad) {
llvm::DiagnosticPrinterRawOStream DiagPrinter(DiagStream);
PrintDiagnosticContext DiagContext(DiagPrinter);
DiagRestore DR(Ctx, &DiagContext);
DiagRestore DR2(DbgCtx, &DiagContext);
const DxilPartHeader *pPart = nullptr;
IFR(FindDxilPart(pContainer, ContainerSize, DFCC_DXIL, &pPart));
const char *pIL = nullptr;
uint32_t ILLength = 0;
GetDxilProgramBitcode(
reinterpret_cast<const DxilProgramHeader *>(GetDxilPartData(pPart)), &pIL,
&ILLength);
IFR(ValidateLoadModule(pIL, ILLength, pModule, Ctx, DiagStream, bLazyLoad));
HRESULT hr;
const DxilPartHeader *pDbgPart = nullptr;
if (FAILED(hr = FindDxilPart(pContainer, ContainerSize,
DFCC_ShaderDebugInfoDXIL, &pDbgPart)) &&
hr != DXC_E_CONTAINER_MISSING_DXIL) {
return hr;
}
if (pDbgPart) {
GetDxilProgramBitcode(
reinterpret_cast<const DxilProgramHeader *>(GetDxilPartData(pDbgPart)),
&pIL, &ILLength);
if (FAILED(hr = ValidateLoadModule(pIL, ILLength, pDebugModule, DbgCtx,
DiagStream, bLazyLoad))) {
return hr;
}
}
return S_OK;
}
HRESULT ValidateLoadModuleFromContainer(
const void *pContainer, uint32_t ContainerSize,
std::unique_ptr<llvm::Module> &pModule,
std::unique_ptr<llvm::Module> &pDebugModule, llvm::LLVMContext &Ctx,
llvm::LLVMContext &DbgCtx, llvm::raw_ostream &DiagStream) {
return ValidateLoadModuleFromContainer(pContainer, ContainerSize, pModule,
pDebugModule, Ctx, DbgCtx, DiagStream,
/*bLazyLoad*/ false);
}
// Lazy loads module from container, validating load, but not module.
HRESULT ValidateLoadModuleFromContainerLazy(
const void *pContainer, uint32_t ContainerSize,
std::unique_ptr<llvm::Module> &pModule,
std::unique_ptr<llvm::Module> &pDebugModule, llvm::LLVMContext &Ctx,
llvm::LLVMContext &DbgCtx, llvm::raw_ostream &DiagStream) {
return ValidateLoadModuleFromContainer(pContainer, ContainerSize, pModule,
pDebugModule, Ctx, DbgCtx, DiagStream,
/*bLazyLoad*/ true);
}
HRESULT ValidateDxilContainer(const void *pContainer, uint32_t ContainerSize,
llvm::Module *pDebugModule,
llvm::raw_ostream &DiagStream) {
LLVMContext Ctx, DbgCtx;
std::unique_ptr<llvm::Module> pModule, pDebugModuleInContainer;
llvm::DiagnosticPrinterRawOStream DiagPrinter(DiagStream);
PrintDiagnosticContext DiagContext(DiagPrinter);
Ctx.setDiagnosticHandler(PrintDiagnosticContext::PrintDiagnosticHandler,
&DiagContext, true);
DbgCtx.setDiagnosticHandler(PrintDiagnosticContext::PrintDiagnosticHandler,
&DiagContext, true);
DiagRestore DR(pDebugModule, &DiagContext);
IFR(ValidateLoadModuleFromContainer(pContainer, ContainerSize, pModule,
pDebugModuleInContainer, Ctx, DbgCtx,
DiagStream));
if (pDebugModuleInContainer)
pDebugModule = pDebugModuleInContainer.get();
// Validate DXIL Module
IFR(ValidateDxilModule(pModule.get(), pDebugModule));
if (DiagContext.HasErrors() || DiagContext.HasWarnings()) {
return DXC_E_IR_VERIFICATION_FAILED;
}
return ValidateDxilContainerParts(
pModule.get(), pDebugModule,
IsDxilContainerLike(pContainer, ContainerSize), ContainerSize);
}
HRESULT ValidateDxilContainer(const void *pContainer, uint32_t ContainerSize,
llvm::raw_ostream &DiagStream) {
return ValidateDxilContainer(pContainer, ContainerSize, nullptr, DiagStream);
}
} // namespace hlsl

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,526 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilValidationUttils.cpp //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// This file provides utils for validating DXIL. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "DxilValidationUtils.h"
#include "dxc/DXIL/DxilEntryProps.h"
#include "dxc/DXIL/DxilInstructions.h"
#include "dxc/DXIL/DxilModule.h"
#include "dxc/DXIL/DxilOperations.h"
#include "dxc/DXIL/DxilUtil.h"
#include "dxc/Support/Global.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Support/raw_ostream.h"
namespace hlsl {
EntryStatus::EntryStatus(DxilEntryProps &entryProps)
: m_bCoverageIn(false), m_bInnerCoverageIn(false), hasViewID(false) {
for (unsigned i = 0; i < DXIL::kNumOutputStreams; i++) {
hasOutputPosition[i] = false;
OutputPositionMask[i] = 0;
}
outputCols.resize(entryProps.sig.OutputSignature.GetElements().size(), 0);
patchConstOrPrimCols.resize(
entryProps.sig.PatchConstOrPrimSignature.GetElements().size(), 0);
}
ValidationContext::ValidationContext(Module &llvmModule, Module *DebugModule,
DxilModule &dxilModule)
: M(llvmModule), pDebugModule(DebugModule), DxilMod(dxilModule),
DL(llvmModule.getDataLayout()), LastRuleEmit((ValidationRule)-1),
kDxilControlFlowHintMDKind(llvmModule.getContext().getMDKindID(
DxilMDHelper::kDxilControlFlowHintMDName)),
kDxilPreciseMDKind(llvmModule.getContext().getMDKindID(
DxilMDHelper::kDxilPreciseAttributeMDName)),
kDxilNonUniformMDKind(llvmModule.getContext().getMDKindID(
DxilMDHelper::kDxilNonUniformAttributeMDName)),
kLLVMLoopMDKind(llvmModule.getContext().getMDKindID("llvm.loop")),
slotTracker(&llvmModule, true) {
DxilMod.GetDxilVersion(m_DxilMajor, m_DxilMinor);
HandleTy = DxilMod.GetOP()->GetHandleType();
for (Function &F : llvmModule.functions()) {
if (DxilMod.HasDxilEntryProps(&F)) {
DxilEntryProps &entryProps = DxilMod.GetDxilEntryProps(&F);
entryStatusMap[&F] = llvm::make_unique<EntryStatus>(entryProps);
}
}
isLibProfile = dxilModule.GetShaderModel()->IsLib();
BuildResMap();
// Collect patch constant map.
if (isLibProfile) {
for (Function &F : dxilModule.GetModule()->functions()) {
if (dxilModule.HasDxilEntryProps(&F)) {
DxilEntryProps &entryProps = dxilModule.GetDxilEntryProps(&F);
DxilFunctionProps &props = entryProps.props;
if (props.IsHS()) {
PatchConstantFuncMap[props.ShaderProps.HS.patchConstantFunc]
.emplace_back(&F);
}
}
}
} else {
Function *Entry = dxilModule.GetEntryFunction();
if (!dxilModule.HasDxilEntryProps(Entry)) {
// must have props.
EmitFnError(Entry, ValidationRule::MetaNoEntryPropsForEntry);
return;
}
DxilEntryProps &entryProps = dxilModule.GetDxilEntryProps(Entry);
DxilFunctionProps &props = entryProps.props;
if (props.IsHS()) {
PatchConstantFuncMap[props.ShaderProps.HS.patchConstantFunc].emplace_back(
Entry);
}
}
}
void ValidationContext::PropagateResMap(Value *V, DxilResourceBase *Res) {
auto it = ResPropMap.find(V);
if (it != ResPropMap.end()) {
DxilResourceProperties RP = resource_helper::loadPropsFromResourceBase(Res);
DxilResourceProperties itRP = it->second;
if (itRP != RP) {
EmitResourceError(Res, ValidationRule::InstrResourceMapToSingleEntry);
}
} else {
DxilResourceProperties RP = resource_helper::loadPropsFromResourceBase(Res);
ResPropMap[V] = RP;
for (User *U : V->users()) {
if (isa<GEPOperator>(U)) {
PropagateResMap(U, Res);
} else if (CallInst *CI = dyn_cast<CallInst>(U)) {
// Stop propagate on function call.
DxilInst_CreateHandleForLib hdl(CI);
if (hdl) {
DxilResourceProperties RP =
resource_helper::loadPropsFromResourceBase(Res);
ResPropMap[CI] = RP;
}
} else if (isa<LoadInst>(U)) {
PropagateResMap(U, Res);
} else if (isa<BitCastOperator>(U) && U->user_empty()) {
// For hlsl type.
continue;
} else {
EmitResourceError(Res, ValidationRule::InstrResourceUser);
}
}
}
}
void ValidationContext::BuildResMap() {
hlsl::OP *hlslOP = DxilMod.GetOP();
if (isLibProfile) {
std::unordered_set<Value *> ResSet;
// Start from all global variable in resTab.
for (auto &Res : DxilMod.GetCBuffers())
PropagateResMap(Res->GetGlobalSymbol(), Res.get());
for (auto &Res : DxilMod.GetUAVs())
PropagateResMap(Res->GetGlobalSymbol(), Res.get());
for (auto &Res : DxilMod.GetSRVs())
PropagateResMap(Res->GetGlobalSymbol(), Res.get());
for (auto &Res : DxilMod.GetSamplers())
PropagateResMap(Res->GetGlobalSymbol(), Res.get());
} else {
// Scan all createHandle.
for (auto &it : hlslOP->GetOpFuncList(DXIL::OpCode::CreateHandle)) {
Function *F = it.second;
if (!F)
continue;
for (User *U : F->users()) {
CallInst *CI = cast<CallInst>(U);
DxilInst_CreateHandle hdl(CI);
// Validate Class/RangeID/Index.
Value *resClass = hdl.get_resourceClass();
if (!isa<ConstantInt>(resClass)) {
EmitInstrError(CI, ValidationRule::InstrOpConstRange);
continue;
}
Value *rangeIndex = hdl.get_rangeId();
if (!isa<ConstantInt>(rangeIndex)) {
EmitInstrError(CI, ValidationRule::InstrOpConstRange);
continue;
}
DxilResourceBase *Res = nullptr;
unsigned rangeId = hdl.get_rangeId_val();
switch (static_cast<DXIL::ResourceClass>(hdl.get_resourceClass_val())) {
default:
EmitInstrError(CI, ValidationRule::InstrOpConstRange);
continue;
break;
case DXIL::ResourceClass::CBuffer:
if (DxilMod.GetCBuffers().size() > rangeId) {
Res = &DxilMod.GetCBuffer(rangeId);
} else {
// Emit Error.
EmitInstrError(CI, ValidationRule::InstrOpConstRange);
continue;
}
break;
case DXIL::ResourceClass::Sampler:
if (DxilMod.GetSamplers().size() > rangeId) {
Res = &DxilMod.GetSampler(rangeId);
} else {
// Emit Error.
EmitInstrError(CI, ValidationRule::InstrOpConstRange);
continue;
}
break;
case DXIL::ResourceClass::SRV:
if (DxilMod.GetSRVs().size() > rangeId) {
Res = &DxilMod.GetSRV(rangeId);
} else {
// Emit Error.
EmitInstrError(CI, ValidationRule::InstrOpConstRange);
continue;
}
break;
case DXIL::ResourceClass::UAV:
if (DxilMod.GetUAVs().size() > rangeId) {
Res = &DxilMod.GetUAV(rangeId);
} else {
// Emit Error.
EmitInstrError(CI, ValidationRule::InstrOpConstRange);
continue;
}
break;
}
ConstantInt *cIndex = dyn_cast<ConstantInt>(hdl.get_index());
if (!Res->GetHLSLType()->getPointerElementType()->isArrayTy()) {
if (!cIndex) {
// index must be 0 for none array resource.
EmitInstrError(CI, ValidationRule::InstrOpConstRange);
continue;
}
}
if (cIndex) {
unsigned index = cIndex->getLimitedValue();
if (index < Res->GetLowerBound() || index > Res->GetUpperBound()) {
// index out of range.
EmitInstrError(CI, ValidationRule::InstrOpConstRange);
continue;
}
}
HandleResIndexMap[CI] = rangeId;
DxilResourceProperties RP =
resource_helper::loadPropsFromResourceBase(Res);
ResPropMap[CI] = RP;
}
}
}
const ShaderModel &SM = *DxilMod.GetShaderModel();
for (auto &it : hlslOP->GetOpFuncList(DXIL::OpCode::AnnotateHandle)) {
Function *F = it.second;
if (!F)
continue;
for (User *U : F->users()) {
CallInst *CI = cast<CallInst>(U);
DxilInst_AnnotateHandle hdl(CI);
DxilResourceProperties RP =
resource_helper::loadPropsFromAnnotateHandle(hdl, SM);
if (RP.getResourceKind() == DXIL::ResourceKind::Invalid) {
EmitInstrError(CI, ValidationRule::InstrOpConstRange);
continue;
}
ResPropMap[CI] = RP;
}
}
}
bool ValidationContext::HasEntryStatus(Function *F) {
return entryStatusMap.find(F) != entryStatusMap.end();
}
EntryStatus &ValidationContext::GetEntryStatus(Function *F) {
return *entryStatusMap[F];
}
CallGraph &ValidationContext::GetCallGraph() {
if (!pCallGraph)
pCallGraph = llvm::make_unique<CallGraph>(M);
return *pCallGraph.get();
}
void ValidationContext::EmitGlobalVariableFormatError(
GlobalVariable *GV, ValidationRule rule, ArrayRef<StringRef> args) {
std::string ruleText = GetValidationRuleText(rule);
FormatRuleText(ruleText, args);
if (pDebugModule)
GV = pDebugModule->getGlobalVariable(GV->getName());
dxilutil::EmitErrorOnGlobalVariable(M.getContext(), GV, ruleText);
Failed = true;
}
// This is the least desirable mechanism, as it has no context.
void ValidationContext::EmitError(ValidationRule rule) {
dxilutil::EmitErrorOnContext(M.getContext(), GetValidationRuleText(rule));
Failed = true;
}
void ValidationContext::FormatRuleText(std::string &ruleText,
ArrayRef<StringRef> args) {
std::string escapedArg;
// Consider changing const char * to StringRef
for (unsigned i = 0; i < args.size(); i++) {
std::string argIdx = "%" + std::to_string(i);
StringRef pArg = args[i];
if (pArg == "")
pArg = "<null>";
if (pArg[0] == 1) {
escapedArg = "";
raw_string_ostream os(escapedArg);
dxilutil::PrintEscapedString(pArg, os);
os.flush();
pArg = escapedArg;
}
std::string::size_type offset = ruleText.find(argIdx);
if (offset == std::string::npos)
continue;
unsigned size = argIdx.size();
ruleText.replace(offset, size, pArg);
}
}
void ValidationContext::EmitFormatError(ValidationRule rule,
ArrayRef<StringRef> args) {
std::string ruleText = GetValidationRuleText(rule);
FormatRuleText(ruleText, args);
dxilutil::EmitErrorOnContext(M.getContext(), ruleText);
Failed = true;
}
void ValidationContext::EmitMetaError(Metadata *Meta, ValidationRule rule) {
std::string O;
raw_string_ostream OSS(O);
Meta->print(OSS, &M);
dxilutil::EmitErrorOnContext(M.getContext(), GetValidationRuleText(rule) + O);
Failed = true;
}
// Use this instead of DxilResourceBase::GetGlobalName
std::string
ValidationContext::GetResourceName(const hlsl::DxilResourceBase *Res) {
if (!Res)
return "nullptr";
std::string resName = Res->GetGlobalName();
if (!resName.empty())
return resName;
if (pDebugModule) {
DxilModule &DM = pDebugModule->GetOrCreateDxilModule();
switch (Res->GetClass()) {
case DXIL::ResourceClass::CBuffer:
return DM.GetCBuffer(Res->GetID()).GetGlobalName();
case DXIL::ResourceClass::Sampler:
return DM.GetSampler(Res->GetID()).GetGlobalName();
case DXIL::ResourceClass::SRV:
return DM.GetSRV(Res->GetID()).GetGlobalName();
case DXIL::ResourceClass::UAV:
return DM.GetUAV(Res->GetID()).GetGlobalName();
default:
return "Invalid Resource";
}
}
// When names have been stripped, use class and binding location to
// identify the resource. Format is roughly:
// Allocated: (CB|T|U|S)<ID>: <ResourceKind> ((cb|t|u|s)<LB>[<RangeSize>]
// space<SpaceID>) Unallocated: (CB|T|U|S)<ID>: <ResourceKind> (no bind
// location) Example: U0: TypedBuffer (u5[2] space1)
// [<RangeSize>] and space<SpaceID> skipped if 1 and 0 respectively.
return (Twine(Res->GetResIDPrefix()) + Twine(Res->GetID()) + ": " +
Twine(Res->GetResKindName()) +
(Res->IsAllocated() ? (" (" + Twine(Res->GetResBindPrefix()) +
Twine(Res->GetLowerBound()) +
(Res->IsUnbounded() ? Twine("[unbounded]")
: (Res->GetRangeSize() != 1)
? "[" + Twine(Res->GetRangeSize()) + "]"
: Twine()) +
((Res->GetSpaceID() != 0)
? " space" + Twine(Res->GetSpaceID())
: Twine()) +
")")
: Twine(" (no bind location)")))
.str();
}
void ValidationContext::EmitResourceError(const hlsl::DxilResourceBase *Res,
ValidationRule rule) {
std::string QuotedRes = " '" + GetResourceName(Res) + "'";
dxilutil::EmitErrorOnContext(M.getContext(),
GetValidationRuleText(rule) + QuotedRes);
Failed = true;
}
void ValidationContext::EmitResourceFormatError(
const hlsl::DxilResourceBase *Res, ValidationRule rule,
ArrayRef<StringRef> args) {
std::string QuotedRes = " '" + GetResourceName(Res) + "'";
std::string ruleText = GetValidationRuleText(rule);
FormatRuleText(ruleText, args);
dxilutil::EmitErrorOnContext(M.getContext(), ruleText + QuotedRes);
Failed = true;
}
bool ValidationContext::IsDebugFunctionCall(Instruction *I) {
return isa<DbgInfoIntrinsic>(I);
}
Instruction *ValidationContext::GetDebugInstr(Instruction *I) {
DXASSERT_NOMSG(I);
if (pDebugModule) {
// Look up the matching instruction in the debug module.
llvm::Function *Fn = I->getParent()->getParent();
llvm::Function *DbgFn = pDebugModule->getFunction(Fn->getName());
if (DbgFn) {
// Linear lookup, but then again, failing validation is rare.
inst_iterator it = inst_begin(Fn);
inst_iterator dbg_it = inst_begin(DbgFn);
while (IsDebugFunctionCall(&*dbg_it))
++dbg_it;
while (&*it != I) {
++it;
++dbg_it;
while (IsDebugFunctionCall(&*dbg_it))
++dbg_it;
}
return &*dbg_it;
}
}
return I;
}
// Emit Error or note on instruction `I` with `Msg`.
// If `isError` is true, `Rule` may omit repeated errors
void ValidationContext::EmitInstrDiagMsg(Instruction *I, ValidationRule Rule,
std::string Msg, bool isError) {
BasicBlock *BB = I->getParent();
Function *F = BB->getParent();
Instruction *DbgI = GetDebugInstr(I);
if (isError) {
if (const DebugLoc L = DbgI->getDebugLoc()) {
// Instructions that get scalarized will likely hit
// this case. Avoid redundant diagnostic messages.
if (Rule == LastRuleEmit && L == LastDebugLocEmit) {
return;
}
LastRuleEmit = Rule;
LastDebugLocEmit = L;
}
dxilutil::EmitErrorOnInstruction(DbgI, Msg);
} else {
dxilutil::EmitNoteOnContext(DbgI->getContext(), Msg);
}
// Add llvm information as a note to instruction string
std::string InstrStr;
raw_string_ostream InstrStream(InstrStr);
I->print(InstrStream, slotTracker);
InstrStream.flush();
StringRef InstrStrRef = InstrStr;
InstrStrRef = InstrStrRef.ltrim(); // Ignore indentation
Msg = "at '" + InstrStrRef.str() + "'";
// Print the parent block name
Msg += " in block '";
if (!BB->getName().empty()) {
Msg += BB->getName();
} else {
unsigned idx = 0;
for (auto i = F->getBasicBlockList().begin(),
e = F->getBasicBlockList().end();
i != e; ++i) {
if (BB == &(*i)) {
break;
}
idx++;
}
Msg += "#" + std::to_string(idx);
}
Msg += "'";
// Print the function name
Msg += " of function '" + F->getName().str() + "'.";
dxilutil::EmitNoteOnContext(DbgI->getContext(), Msg);
Failed = true;
}
void ValidationContext::EmitInstrError(Instruction *I, ValidationRule rule) {
EmitInstrDiagMsg(I, rule, GetValidationRuleText(rule));
}
void ValidationContext::EmitInstrNote(Instruction *I, std::string Msg) {
EmitInstrDiagMsg(I, LastRuleEmit, Msg, false);
}
void ValidationContext::EmitInstrFormatError(Instruction *I,
ValidationRule rule,
ArrayRef<StringRef> args) {
std::string ruleText = GetValidationRuleText(rule);
FormatRuleText(ruleText, args);
EmitInstrDiagMsg(I, rule, ruleText);
}
void ValidationContext::EmitSignatureError(DxilSignatureElement *SE,
ValidationRule rule) {
EmitFormatError(rule, {SE->GetName()});
}
void ValidationContext::EmitTypeError(Type *Ty, ValidationRule rule) {
std::string O;
raw_string_ostream OSS(O);
Ty->print(OSS);
EmitFormatError(rule, {OSS.str()});
}
void ValidationContext::EmitFnError(Function *F, ValidationRule rule) {
if (pDebugModule)
if (Function *dbgF = pDebugModule->getFunction(F->getName()))
F = dbgF;
dxilutil::EmitErrorOnFunction(M.getContext(), F, GetValidationRuleText(rule));
Failed = true;
}
void ValidationContext::EmitFnFormatError(Function *F, ValidationRule rule,
ArrayRef<StringRef> args) {
std::string ruleText = GetValidationRuleText(rule);
FormatRuleText(ruleText, args);
if (pDebugModule)
if (Function *dbgF = pDebugModule->getFunction(F->getName()))
F = dbgF;
dxilutil::EmitErrorOnFunction(M.getContext(), F, ruleText);
Failed = true;
}
void ValidationContext::EmitFnAttributeError(Function *F, StringRef Kind,
StringRef Value) {
EmitFnFormatError(F, ValidationRule::DeclFnAttribute,
{F->getName(), Kind, Value});
}
} // namespace hlsl

Просмотреть файл

@ -0,0 +1,149 @@
///////////////////////////////////////////////////////////////////////////////
// //
// DxilValidationUttils.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// This file provides utils for validating DXIL. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include "dxc/DXIL/DxilConstants.h"
#include "dxc/DXIL/DxilResourceProperties.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/ModuleSlotTracker.h"
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace llvm;
namespace llvm {
class Module;
class Function;
class DataLayout;
class Metadata;
class Value;
class GlobalVariable;
class Instruction;
class Type;
} // namespace llvm
namespace hlsl {
///////////////////////////////////////////////////////////////////////////////
// Validation rules.
#include "DxilValidation.inc"
const char *GetValidationRuleText(ValidationRule value);
class DxilEntryProps;
class DxilModule;
class DxilResourceBase;
class DxilSignatureElement;
// Save status like output write for entries.
struct EntryStatus {
bool hasOutputPosition[DXIL::kNumOutputStreams];
unsigned OutputPositionMask[DXIL::kNumOutputStreams];
std::vector<unsigned> outputCols;
std::vector<unsigned> patchConstOrPrimCols;
bool m_bCoverageIn, m_bInnerCoverageIn;
bool hasViewID;
unsigned domainLocSize;
EntryStatus(DxilEntryProps &entryProps);
};
struct ValidationContext {
bool Failed = false;
Module &M;
Module *pDebugModule;
DxilModule &DxilMod;
const Type *HandleTy;
const DataLayout &DL;
DebugLoc LastDebugLocEmit;
ValidationRule LastRuleEmit;
std::unordered_set<Function *> entryFuncCallSet;
std::unordered_set<Function *> patchConstFuncCallSet;
std::unordered_map<unsigned, bool> UavCounterIncMap;
std::unordered_map<Value *, unsigned> HandleResIndexMap;
// TODO: save resource map for each createHandle/createHandleForLib.
std::unordered_map<Value *, DxilResourceProperties> ResPropMap;
std::unordered_map<Function *, std::vector<Function *>> PatchConstantFuncMap;
std::unordered_map<Function *, std::unique_ptr<EntryStatus>> entryStatusMap;
bool isLibProfile;
const unsigned kDxilControlFlowHintMDKind;
const unsigned kDxilPreciseMDKind;
const unsigned kDxilNonUniformMDKind;
const unsigned kLLVMLoopMDKind;
unsigned m_DxilMajor, m_DxilMinor;
ModuleSlotTracker slotTracker;
std::unique_ptr<CallGraph> pCallGraph;
ValidationContext(Module &llvmModule, Module *DebugModule,
DxilModule &dxilModule);
void PropagateResMap(Value *V, DxilResourceBase *Res);
void BuildResMap();
bool HasEntryStatus(Function *F);
EntryStatus &GetEntryStatus(Function *F);
CallGraph &GetCallGraph();
DxilResourceProperties GetResourceFromVal(Value *resVal);
void EmitGlobalVariableFormatError(GlobalVariable *GV, ValidationRule rule,
ArrayRef<StringRef> args);
// This is the least desirable mechanism, as it has no context.
void EmitError(ValidationRule rule);
void FormatRuleText(std::string &ruleText, ArrayRef<StringRef> args);
void EmitFormatError(ValidationRule rule, ArrayRef<StringRef> args);
void EmitMetaError(Metadata *Meta, ValidationRule rule);
// Use this instead of DxilResourceBase::GetGlobalName
std::string GetResourceName(const hlsl::DxilResourceBase *Res);
void EmitResourceError(const hlsl::DxilResourceBase *Res,
ValidationRule rule);
void EmitResourceFormatError(const hlsl::DxilResourceBase *Res,
ValidationRule rule, ArrayRef<StringRef> args);
bool IsDebugFunctionCall(Instruction *I);
Instruction *GetDebugInstr(Instruction *I);
// Emit Error or note on instruction `I` with `Msg`.
// If `isError` is true, `Rule` may omit repeated errors
void EmitInstrDiagMsg(Instruction *I, ValidationRule Rule, std::string Msg,
bool isError = true);
void EmitInstrError(Instruction *I, ValidationRule rule);
void EmitInstrNote(Instruction *I, std::string Msg);
void EmitInstrFormatError(Instruction *I, ValidationRule rule,
ArrayRef<StringRef> args);
void EmitSignatureError(DxilSignatureElement *SE, ValidationRule rule);
void EmitTypeError(Type *Ty, ValidationRule rule);
void EmitFnError(Function *F, ValidationRule rule);
void EmitFnFormatError(Function *F, ValidationRule rule,
ArrayRef<StringRef> args);
void EmitFnAttributeError(Function *F, StringRef Kind, StringRef Value);
};
uint32_t ValidateDxilModule(llvm::Module *pModule, llvm::Module *pDebugModule);
} // namespace hlsl

Просмотреть файл

@ -2,7 +2,6 @@
# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details.
add_hlsl_hctgen(DxcOptimizer OUTPUT DxcOptimizer.inc BUILD_DIR)
add_hlsl_hctgen(DxilValidation OUTPUT DxilValidationImpl.inc BUILD_DIR)
add_llvm_library(LLVMHLSL
ComputeViewIdState.cpp
@ -32,7 +31,6 @@ add_llvm_library(LLVMHLSL
DxilTargetTransformInfo.cpp
DxilTranslateRawBuffer.cpp
DxilExportMap.cpp
DxilValidation.cpp
DxcOptimizer.cpp
HLDeadFunctionElimination.cpp
HLExpandStoreIntrinsics.cpp

Просмотреть файл

@ -11,33 +11,13 @@
///////////////////////////////////////////////////////////////////////////////
#include "dxc/DXIL/DxilInstructions.h"
#include "dxc/DXIL/DxilModule.h"
#include "dxc/DXIL/DxilOperations.h"
#include "dxc/DXIL/DxilShaderModel.h"
#include "dxc/DxilContainer/DxilContainer.h"
#include "dxc/HLSL/DxilGenerationPass.h"
#include "dxc/HLSL/DxilValidation.h"
#include "dxc/HLSL/HLModule.h"
#include "dxc/HLSL/HLOperations.h"
#include "dxc/Support/Global.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#ifdef _WIN32
#include <winerror.h>
#endif
#include "llvm/Support/raw_ostream.h"
#include <unordered_set>
using namespace llvm;
using std::map;

Просмотреть файл

@ -13,7 +13,7 @@ target_link_libraries(dxilconv PRIVATE
LLVMDXIL
LLVMDxilContainer
LLVMDxilRootSignature
LLVMHLSL
LLVMDxilValidation
LLVMMSSupport
LLVMScalarOpts
)
@ -23,4 +23,4 @@ set_target_properties(dxilconv
OUTPUT_NAME "dxilconv"
)
add_dependencies(dxilconv DxcEtw)
add_dependencies(dxilconv DxcEtw)

Просмотреть файл

@ -23,8 +23,8 @@
#include "llvm/ADT/SmallVector.h"
#include <algorithm>
#include "dxc/DxilValidation/DxilValidation.h"
#include "dxc/HLSL/DxilLinker.h"
#include "dxc/HLSL/DxilValidation.h"
#include "dxc/Support/HLSLOptions.h"
#include "dxc/Support/Unicode.h"
#include "dxc/Support/microcom.h"

Просмотреть файл

@ -7,7 +7,7 @@ set( LLVM_LINK_COMPONENTS
dxcsupport
DXIL
DxilContainer
HLSL
DxilValidation
Option # option library
Support # just for assert and raw streams
)

Просмотреть файл

@ -14,7 +14,7 @@
#include "llvm/IR/LLVMContext.h"
#include "dxc/DxilContainer/DxilContainer.h"
#include "dxc/HLSL/DxilValidation.h"
#include "dxc/DxilValidation/DxilValidation.h"
#include "dxc/Support/WinIncludes.h"
#include "dxc/dxcapi.h"
#include "dxcvalidator.h"

Просмотреть файл

@ -21,7 +21,7 @@
#include "dxc/HLSL/DxilLinker.h"
#include "dxc/DXIL/DxilModule.h"
#include "dxc/DXIL/DxilUtil.h"
#include "dxc/HLSL/DxilValidation.h"
#include "dxc/DxilValidation/DxilValidation.h"
#include "dxc/Support/FileIOHelper.h"
#include "dxc/Support/dxcapi.impl.h"
#include "dxcutil.h"

Просмотреть файл

@ -1941,7 +1941,6 @@ if __name__ == "__main__":
"lib/DXIL/DxilShaderModel.cpp",
"include/dxc/DXIL/DxilConstants.h",
"include/dxc/DXIL/DxilShaderModel.h",
"include/dxc/HLSL/DxilValidation.h",
"include/dxc/Support/HLSLOptions.td",
"include/dxc/DXIL/DxilInstructions.h",
"lib/HLSL/DxcOptimizer.cpp",