Fold bitcast-to-base into GEP in MergeGepUse, plus refactor and resource fixes (#3801)

* Fold bitcast-to-base into GEP in MergeGepUse, plus refactor

  - Fixes case where bitcast isn't eliminated under -Od.
  - Fix issue with constant GEP path that was unintentionally using GEP
    from failed prior branch.
  - Change to worklist pattern, which simplifies things.
  - One case wasn't handled, which was going to complicate code:
    GEP -> bitcast -> GEP would combine bitcast -> GEP, but not combine
    outer GEP with the new one.
  - Add dxilutil::TryReplaceBaseCastWithGep that simply replaces if it matches.

* Fix cbuffer layouts when resources are in structs

  - keep track of resources in type annotation information
  - fix cbuffer packing locations for things around resources
  - when translating struct for legacy:
    - remove resource fields from struct types
    - properly replace HLSL type
  - remove unused structs and annotations
  - don't produce type annotations for silly things
  - fix other random bugs found along the way

* Fix ValidateVersionNotAllowed test issue with external validator

  It turns out the test wasn't correct in assuming dxil version reported was
  the one it should expect to be supported by the validator, since that
  represents the compiler version.  The validator version constrains the
  dxil version supported by the validator, not the compiler version.
  See comments in the test for details.

* Fix error reporting in ValidationTest::RewriteAssemblyToText

* Fix tests for translated structs and hostlayout name change.
This commit is contained in:
Tex Riddell 2021-05-26 20:17:50 -07:00 коммит произвёл GitHub
Родитель 0669cbfaf5
Коммит e6ba792e2d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
21 изменённых файлов: 592 добавлений и 138 удалений

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

@ -27,7 +27,6 @@ class Function;
class MDNode;
class Type;
class StructType;
class StringRef;
}
@ -95,7 +94,7 @@ private:
bool m_bCBufferVarUsed; // true if this field represents a top level variable in CB structure, and it is used.
};
class DxilTemplateArgAnnotation : DxilFieldAnnotation {
class DxilTemplateArgAnnotation {
public:
DxilTemplateArgAnnotation();
@ -126,6 +125,10 @@ public:
void SetCBufferSize(unsigned size);
void MarkEmptyStruct();
bool IsEmptyStruct();
// Since resources don't take real space, IsEmptyBesidesResources
// determines if the structure is empty or contains only resources.
bool IsEmptyBesidesResources();
bool ContainsResources() const;
// For template args, GetNumTemplateArgs() will return 0 if not a template
unsigned GetNumTemplateArgs() const;
@ -134,10 +137,15 @@ public:
const DxilTemplateArgAnnotation &GetTemplateArgAnnotation(unsigned argIdx) const;
private:
const llvm::StructType *m_pStructType;
const llvm::StructType *m_pStructType = nullptr;
std::vector<DxilFieldAnnotation> m_FieldAnnotations;
unsigned m_CBufferSize; // The size of struct if inside constant buffer.
unsigned m_CBufferSize = 0; // The size of struct if inside constant buffer.
std::vector<DxilTemplateArgAnnotation> m_TemplateAnnotations;
// m_ResourcesContained property not stored to metadata
void SetContainsResources();
// HasResources::Only will be set on MarkEmptyStruct() when HasResources::True
enum class HasResources { True, False, Only } m_ResourcesContained = HasResources::False;
};
@ -223,10 +231,17 @@ public:
const llvm::Function *GetFunction() const;
DxilParameterAnnotation &GetRetTypeAnnotation();
const DxilParameterAnnotation &GetRetTypeAnnotation() const;
bool ContainsResourceArgs() { return m_bContainsResourceArgs; }
private:
const llvm::Function *m_pFunction;
std::vector<DxilParameterAnnotation> m_parameterAnnotations;
DxilParameterAnnotation m_retTypeAnnotation;
// m_bContainsResourceArgs property not stored to metadata
void SetContainsResourceArgs() { m_bContainsResourceArgs = true; }
bool m_bContainsResourceArgs = false;
};
/// Use this class to represent structure type annotations in HL and DXIL.
@ -239,9 +254,11 @@ public:
DxilTypeSystem(llvm::Module *pModule);
DxilStructAnnotation *AddStructAnnotation(const llvm::StructType *pStructType, unsigned numTemplateArgs = 0);
void FinishStructAnnotation(DxilStructAnnotation &SA);
DxilStructAnnotation *GetStructAnnotation(const llvm::StructType *pStructType);
const DxilStructAnnotation *GetStructAnnotation(const llvm::StructType *pStructType) const;
void EraseStructAnnotation(const llvm::StructType *pStructType);
void EraseUnusedStructAnnotations();
StructAnnotationMap &GetStructAnnotationMap();
const StructAnnotationMap &GetStructAnnotationMap() const;
@ -255,6 +272,7 @@ public:
const PayloadAnnotationMap &GetPayloadAnnotationMap() const;
DxilFunctionAnnotation *AddFunctionAnnotation(const llvm::Function *pFunction);
void FinishFunctionAnnotation(DxilFunctionAnnotation &FA);
DxilFunctionAnnotation *GetFunctionAnnotation(const llvm::Function *pFunction);
const DxilFunctionAnnotation *GetFunctionAnnotation(const llvm::Function *pFunction) const;
void EraseFunctionAnnotation(const llvm::Function *pFunction);
@ -275,6 +293,9 @@ public:
bool UseMinPrecision();
void SetMinPrecision(bool bMinPrecision);
// Determines whether type is a resource or contains a resource
bool IsResourceContained(llvm::Type *Ty);
private:
llvm::Module *m_pModule;
StructAnnotationMap m_StructAnnotations;

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

@ -155,6 +155,12 @@ namespace dxilutil {
bool IsConvergentMarker(llvm::Value *V);
llvm::Value *GetConvergentSource(llvm::Value *V);
/// If value is a bitcast to base class pattern, equivalent
/// to a getelementptr X, 0, 0, 0... turn it into the appropriate gep.
/// This can enhance SROA and other transforms that want type-safe pointers,
/// and enables merging with other getelementptr's.
llvm::Value *TryReplaceBaseCastWithGep(llvm::Value *V);
}
}

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

@ -842,6 +842,7 @@ void DxilMDHelper::LoadDxilTypeSystemNode(const llvm::MDTuple &MDT,
DxilStructAnnotation *pSA = TypeSystem.AddStructAnnotation(pGVType);
LoadDxilStructAnnotation(MDT.getOperand(i + 1), *pSA);
TypeSystem.FinishStructAnnotation(*pSA);
}
} else {
IFTBOOL((MDT.getNumOperands() & 0x1) == 1, DXC_E_INCORRECT_DXIL_METADATA);
@ -849,6 +850,7 @@ void DxilMDHelper::LoadDxilTypeSystemNode(const llvm::MDTuple &MDT,
Function *F = dyn_cast<Function>(ValueMDToValue(MDT.getOperand(i)));
DxilFunctionAnnotation *pFA = TypeSystem.AddFunctionAnnotation(F);
LoadDxilFunctionAnnotation(MDT.getOperand(i + 1), *pFA);
TypeSystem.FinishFunctionAnnotation(*pFA);
}
}
}

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

@ -9,6 +9,7 @@
#include "dxc/DXIL/DxilTypeSystem.h"
#include "dxc/DXIL/DxilModule.h"
#include "dxc/DXIL/DxilUtil.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/WinFunctions.h"
@ -149,7 +150,7 @@ bool DxilPayloadFieldAnnotation::HasAnnotations() const {
// DxilStructAnnotation class methods.
//
DxilTemplateArgAnnotation::DxilTemplateArgAnnotation()
: DxilFieldAnnotation(), m_Type(nullptr), m_Integral(0)
: m_Type(nullptr), m_Integral(0)
{}
bool DxilTemplateArgAnnotation::IsType() const { return m_Type != nullptr; }
@ -182,8 +183,26 @@ void DxilStructAnnotation::SetStructType(const llvm::StructType *Ty) {
unsigned DxilStructAnnotation::GetCBufferSize() const { return m_CBufferSize; }
void DxilStructAnnotation::SetCBufferSize(unsigned size) { m_CBufferSize = size; }
void DxilStructAnnotation::MarkEmptyStruct() { m_FieldAnnotations.clear(); }
bool DxilStructAnnotation::IsEmptyStruct() { return m_FieldAnnotations.empty(); }
void DxilStructAnnotation::MarkEmptyStruct() {
if (m_ResourcesContained == HasResources::True)
m_ResourcesContained = HasResources::Only;
else
m_FieldAnnotations.clear();
}
bool DxilStructAnnotation::IsEmptyStruct() {
return m_FieldAnnotations.empty();
}
bool DxilStructAnnotation::IsEmptyBesidesResources() {
return m_ResourcesContained == HasResources::Only ||
m_FieldAnnotations.empty();
}
// ContainsResources is for codegen only, not meant for metadata
void DxilStructAnnotation::SetContainsResources() {
if (m_ResourcesContained == HasResources::False)
m_ResourcesContained = HasResources::True;
}
bool DxilStructAnnotation::ContainsResources() const { return m_ResourcesContained != HasResources::False; }
// For template args, GetNumTemplateArgs() will return 0 if not a template
unsigned DxilStructAnnotation::GetNumTemplateArgs() const {
@ -200,7 +219,6 @@ const DxilTemplateArgAnnotation &DxilStructAnnotation::GetTemplateArgAnnotation(
return m_TemplateAnnotations[argIdx];
}
//------------------------------------------------------------------------------
//
// DxilParameterAnnotation class methods.
@ -297,6 +315,21 @@ DxilStructAnnotation *DxilTypeSystem::AddStructAnnotation(const StructType *pStr
return pA;
}
void DxilTypeSystem::FinishStructAnnotation(DxilStructAnnotation &SA) {
const llvm::StructType *ST = SA.GetStructType();
DXASSERT(SA.GetNumFields() == ST->getNumElements(), "otherwise, mismatched field count.");
// Update resource containment
for (unsigned i = 0; i < SA.GetNumFields() && !SA.ContainsResources(); i++) {
if (IsResourceContained(ST->getElementType(i)))
SA.SetContainsResources();
}
// Mark if empty
if (SA.GetCBufferSize() == 0)
SA.MarkEmptyStruct();
}
DxilStructAnnotation *DxilTypeSystem::GetStructAnnotation(const StructType *pStructType) {
auto it = m_StructAnnotations.find(pStructType);
if (it != m_StructAnnotations.end()) {
@ -323,6 +356,57 @@ void DxilTypeSystem::EraseStructAnnotation(const StructType *pStructType) {
&I) { return pStructType == I.first; });
}
// Recurse type, removing any found StructType from the set
static void RemoveUsedStructsFromSet(Type *Ty, std::unordered_set<const llvm::StructType*> &unused_structs) {
if (Ty->isPointerTy())
RemoveUsedStructsFromSet(Ty->getPointerElementType(), unused_structs);
else if (Ty->isArrayTy())
RemoveUsedStructsFromSet(Ty->getArrayElementType(), unused_structs);
else if (Ty->isStructTy()) {
StructType *ST = cast<StructType>(Ty);
// Only recurse first time into this struct
if (unused_structs.erase(ST)) {
for (auto &ET : ST->elements()) {
RemoveUsedStructsFromSet(ET, unused_structs);
}
}
}
}
void DxilTypeSystem::EraseUnusedStructAnnotations() {
// Add all structures with annotations to a set
// Iterate globals, resource types, and functions, recursing used structures to
// remove matching struct annotations from set
std::unordered_set<const llvm::StructType*> unused_structs;
for (auto &it : m_StructAnnotations) {
unused_structs.insert(it.first);
}
for (auto &GV : m_pModule->globals()) {
RemoveUsedStructsFromSet(GV.getType(), unused_structs);
}
DxilModule &DM = m_pModule->GetDxilModule();
for (auto &&C : DM.GetCBuffers()) {
RemoveUsedStructsFromSet(C->GetHLSLType(), unused_structs);
}
for (auto &&Srv : DM.GetSRVs()) {
RemoveUsedStructsFromSet(Srv->GetHLSLType(), unused_structs);
}
for (auto &&Uav : DM.GetUAVs()) {
RemoveUsedStructsFromSet(Uav->GetHLSLType(), unused_structs);
}
for (auto &F : m_pModule->functions()) {
FunctionType *FT = F.getFunctionType();
RemoveUsedStructsFromSet(FT->getReturnType(), unused_structs);
for (auto &argTy : FT->params()) {
RemoveUsedStructsFromSet(argTy, unused_structs);
}
}
// erase remaining structures in set
for (auto *ST : unused_structs) {
EraseStructAnnotation(ST);
}
}
DxilTypeSystem::StructAnnotationMap &DxilTypeSystem::GetStructAnnotationMap() {
return m_StructAnnotations;
}
@ -383,6 +467,18 @@ DxilFunctionAnnotation *DxilTypeSystem::AddFunctionAnnotation(const Function *pF
return pA;
}
void DxilTypeSystem::FinishFunctionAnnotation(DxilFunctionAnnotation &FA) {
auto FT = FA.GetFunction()->getFunctionType();
// Update resource containment
if (IsResourceContained(FT->getReturnType()))
FA.SetContainsResourceArgs();
for (unsigned i = 0; i < FT->getNumParams() && !FA.ContainsResourceArgs(); i++) {
if (IsResourceContained(FT->getParamType(i)))
FA.SetContainsResourceArgs();
}
}
DxilFunctionAnnotation *DxilTypeSystem::GetFunctionAnnotation(const Function *pFunction) {
auto it = m_FunctionAnnotations.find(pFunction);
if (it != m_FunctionAnnotations.end()) {
@ -659,6 +755,24 @@ void DxilTypeSystem::SetMinPrecision(bool bMinPrecision) {
m_LowPrecisionMode = mode;
}
bool DxilTypeSystem::IsResourceContained(llvm::Type *Ty) {
// strip pointer/array
if (Ty->isPointerTy())
Ty = Ty->getPointerElementType();
if (Ty->isArrayTy())
Ty = Ty->getArrayElementType();
if (auto ST = dyn_cast<StructType>(Ty)) {
if (dxilutil::IsHLSLResourceType(Ty)) {
return true;
} else if (auto SA = GetStructAnnotation(ST)) {
if (SA->ContainsResources())
return true;
}
}
return false;
}
DxilStructTypeIterator::DxilStructTypeIterator(llvm::StructType *sTy, DxilStructAnnotation *sAnnotation,
unsigned idx)
: STy(sTy), SAnnotation(sAnnotation), index(idx) {

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

@ -1192,6 +1192,47 @@ Value *GetConvergentSource(Value *V) {
return cast<CallInst>(V)->getOperand(0);
}
/// If value is a bitcast to base class pattern, equivalent
/// to a getelementptr X, 0, 0, 0... turn it into the appropriate gep.
/// This can enhance SROA and other transforms that want type-safe pointers,
/// and enables merging with other getelementptr's.
Value *TryReplaceBaseCastWithGep(Value *V) {
if (BitCastOperator *BCO = dyn_cast<BitCastOperator>(V)) {
if (!BCO->getSrcTy()->isPointerTy())
return nullptr;
Type *SrcElTy = BCO->getSrcTy()->getPointerElementType();
Type *DstElTy = BCO->getDestTy()->getPointerElementType();
// Adapted from code in InstCombiner::visitBitCast
unsigned NumZeros = 0;
while (SrcElTy != DstElTy && isa<CompositeType>(SrcElTy) &&
!SrcElTy->isPointerTy() &&
SrcElTy->getNumContainedTypes() /* not "{}" */) {
SrcElTy = cast<CompositeType>(SrcElTy)->getTypeAtIndex(0U);
++NumZeros;
}
// If we found a path from the src to dest, create the getelementptr now.
if (SrcElTy == DstElTy) {
IRBuilder<> Builder(BCO->getContext());
StringRef Name = "";
if (Instruction *I = dyn_cast<Instruction>(BCO)) {
Builder.SetInsertPoint(I);
Name = I->getName();
}
SmallVector<Value *, 8> Indices(NumZeros + 1, Builder.getInt32(0));
Value *newGEP = Builder.CreateInBoundsGEP(nullptr, BCO->getOperand(0), Indices, Name);
V->replaceAllUsesWith(newGEP);
if (auto *I = dyn_cast<Instruction>(V))
I->eraseFromParent();
return newGEP;
}
}
return nullptr;
}
}
}

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

@ -581,6 +581,9 @@ public:
dxilutil::RemoveUnusedFunctions(M, DM.GetEntryFunction(),
DM.GetPatchConstantFunction(), m_bIsLib);
// Erase type annotations for structures no longer used
DM.GetTypeSystem().EraseUnusedStructAnnotations();
return bChanged;
}
@ -1620,7 +1623,8 @@ bool DxilLowerCreateHandleForLib::RemovePhiOnResource() {
namespace {
StructType *UpdateStructTypeForLegacyLayout(StructType *ST,
DxilTypeSystem &TypeSys, Module &M);
DxilTypeSystem &TypeSys, Module &M,
bool includeTopLevelResource=false);
Type *UpdateFieldTypeForLegacyLayout(Type *Ty,
DxilFieldAnnotation &annotation,
@ -1633,8 +1637,10 @@ Type *UpdateFieldTypeForLegacyLayout(Type *Ty,
UpdateFieldTypeForLegacyLayout(EltTy, annotation, TypeSys, M);
if (EltTy == UpdatedTy)
return Ty;
else
else if (UpdatedTy)
return ArrayType::get(UpdatedTy, Ty->getArrayNumElements());
else
return nullptr;
} else if (hlsl::HLMatrixType::isa(Ty)) {
DXASSERT(annotation.HasMatrixAnnotation(), "must a matrix");
HLMatrixType MatTy = HLMatrixType::cast(Ty);
@ -1690,12 +1696,17 @@ Type *UpdateFieldTypeForLegacyLayout(Type *Ty,
StructType *UpdateStructTypeForLegacyLayout(StructType *ST,
DxilTypeSystem &TypeSys,
Module &M) {
Module &M,
bool includeTopLevelResource) {
bool bUpdated = false;
unsigned fieldsCount = ST->getNumElements();
std::vector<Type *> fieldTypes(fieldsCount);
std::vector<Type *> fieldTypes;
fieldTypes.reserve(fieldsCount);
DxilStructAnnotation *SA = TypeSys.GetStructAnnotation(ST);
if (!includeTopLevelResource && dxilutil::IsHLSLResourceType(ST))
return nullptr;
// After reflection is stripped from library, this will be null if no update is required.
if (!SA) {
return ST;
@ -1705,11 +1716,20 @@ StructType *UpdateStructTypeForLegacyLayout(StructType *ST,
return ST;
}
// Resource fields must be deleted, since they don't actually
// show up in the structure layout.
// fieldMap maps from new field index to old field index for porting annotations
std::vector<unsigned> fieldMap;
fieldMap.reserve(fieldsCount);
for (unsigned i = 0; i < fieldsCount; i++) {
Type *EltTy = ST->getElementType(i);
Type *UpdatedTy = UpdateFieldTypeForLegacyLayout(
EltTy, SA->GetFieldAnnotation(i), TypeSys, M);
fieldTypes[i] = UpdatedTy;
if (UpdatedTy != nullptr) {
fieldMap.push_back(i);
fieldTypes.push_back(UpdatedTy);
}
if (EltTy != UpdatedTy)
bUpdated = true;
}
@ -1723,12 +1743,24 @@ StructType *UpdateStructTypeForLegacyLayout(StructType *ST,
StructType *NewST =
StructType::create(ST->getContext(), fieldTypes, legacyName);
DxilStructAnnotation *NewSA = TypeSys.AddStructAnnotation(NewST);
// Clone annotation.
*NewSA = *SA;
// Make sure we set the struct type back to the new one, since the
// clone would have clobbered it with the old one.
NewSA->SetStructType(NewST);
// Only add annotation if struct is not empty.
if (NewST->getNumElements() > 0) {
DxilStructAnnotation *NewSA = TypeSys.AddStructAnnotation(NewST);
// Clone annotation.
NewSA->SetCBufferSize(SA->GetCBufferSize());
NewSA->SetNumTemplateArgs(SA->GetNumTemplateArgs());
for (unsigned i = 0; i < SA->GetNumTemplateArgs(); i++) {
NewSA->GetTemplateArgAnnotation(i) = SA->GetTemplateArgAnnotation(i);
}
// Remap with deleted resource fields
for (unsigned i = 0; i < NewSA->GetNumFields(); i++) {
NewSA->GetFieldAnnotation(i) = SA->GetFieldAnnotation(fieldMap[i]);
}
TypeSys.FinishStructAnnotation(*NewSA);
}
return NewST;
}
}
@ -1749,13 +1781,15 @@ bool UpdateStructTypeForLegacyLayout(DxilResourceBase &Res,
}
Type *UpdatedST =
UpdateStructTypeForLegacyLayout(ST, TypeSys, M);
UpdateStructTypeForLegacyLayout(ST, TypeSys, M,
Res.GetKind() == DXIL::ResourceKind::StructuredBuffer);
if (ST != UpdatedST) {
// Support Array of ConstantBuffer/StructuredBuffer.
UpdatedST = dxilutil::WrapInArrayTypes(UpdatedST, arrayDims);
GlobalVariable *NewGV = cast<GlobalVariable>(
M.getOrInsertGlobal(Symbol->getName().str() + "_legacy", UpdatedST));
Res.SetGlobalSymbol(NewGV);
Res.SetHLSLType(NewGV->getType());
OP *hlslOP = DM.GetOP();
if (DM.GetShaderModel()->IsLib()) {
@ -1862,6 +1896,8 @@ void DxilLowerCreateHandleForLib::UpdateResourceSymbols() {
GV->removeDeadConstantUsers();
DXASSERT(GV->user_empty(), "else resource not lowered");
res->SetGlobalSymbol(UndefValue::get(GV->getType()));
if (GV->user_empty())
GV->eraseFromParent();
}
};

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

@ -1097,7 +1097,7 @@ HRESULT CShaderReflectionType::Initialize(
// There is no annotation for empty structs
unsigned int fieldCount = 0;
if (structAnnotation)
if (structAnnotation && !structAnnotation->IsEmptyBesidesResources())
fieldCount = type->getStructNumElements();
// The DXBC reflection info computes `Columns` for a
@ -1128,6 +1128,13 @@ HRESULT CShaderReflectionType::Initialize(
m_MemberTypes.push_back(fieldReflectionType);
m_MemberNames.push_back(fieldAnnotation.GetFieldName().c_str());
// Skip structures fields with no real contents, otherwise we expand
// the size of this struct by 1 when we treat a zero column size as 1.
if (isa<StructType>(fieldType) &&
fieldReflectionType->m_Desc.Columns == 0) {
continue;
}
// Effectively, we want to add one to `Columns` for every scalar nested recursively
// inside this `struct` type (ignoring objects, which we filtered above). We should
// be able to compute this as the product of the `Columns`, `Rows` and `Elements`

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

@ -980,8 +980,13 @@ void HLModule::GetParameterRowsAndCols(Type *Ty, unsigned &rows, unsigned &cols,
rows *= arraySize;
}
static Value *MergeGEP(GEPOperator *SrcGEP, GetElementPtrInst *GEP) {
IRBuilder<> Builder(GEP);
static Value *MergeGEP(GEPOperator *SrcGEP, GEPOperator *GEP) {
IRBuilder<> Builder(GEP->getContext());
StringRef Name = "";
if (Instruction *I = dyn_cast<Instruction>(GEP)) {
Builder.SetInsertPoint(I);
Name = GEP->getName();
}
SmallVector<Value *, 8> Indices;
// Find out whether the last index in the source GEP is a sequential idx.
@ -1028,51 +1033,52 @@ static Value *MergeGEP(GEPOperator *SrcGEP, GetElementPtrInst *GEP) {
Indices.append(SrcGEP->op_begin() + 1, SrcGEP->op_end());
Indices.append(GEP->idx_begin() + 1, GEP->idx_end());
}
if (!Indices.empty())
return Builder.CreateInBoundsGEP(SrcGEP->getSourceElementType(),
SrcGEP->getOperand(0), Indices,
GEP->getName());
else
llvm_unreachable("must merge");
DXASSERT(!Indices.empty(), "must merge");
Value *newGEP = Builder.CreateInBoundsGEP(nullptr, SrcGEP->getOperand(0), Indices, Name);
GEP->replaceAllUsesWith(newGEP);
if (Instruction *I = dyn_cast<Instruction>(GEP))
I->eraseFromParent();
return newGEP;
}
void HLModule::MergeGepUse(Value *V) {
for (auto U = V->user_begin(); U != V->user_end();) {
auto Use = U++;
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(*Use)) {
if (GEPOperator *prevGEP = dyn_cast<GEPOperator>(V)) {
// merge the 2 GEPs
Value *newGEP = MergeGEP(prevGEP, GEP);
// Don't need to replace when GEP is updated in place
if (newGEP != GEP) {
GEP->replaceAllUsesWith(newGEP);
GEP->eraseFromParent();
}
MergeGepUse(newGEP);
SmallVector<Value*, 16> worklist;
auto addUsersToWorklist = [&worklist](Value *V) {
if (!V->user_empty()) {
// Add users in reverse to the worklist, so they are processed in order
// This makes it equivalent to recursive traversal
size_t start = worklist.size();
worklist.append(V->user_begin(), V->user_end());
size_t end = worklist.size();
std::reverse(worklist.data() + start, worklist.data() + end);
}
};
addUsersToWorklist(V);
while (worklist.size()) {
V = worklist.pop_back_val();
if (BitCastOperator *BCO = dyn_cast<BitCastOperator>(V)) {
if (Value *NewV = dxilutil::TryReplaceBaseCastWithGep(V)) {
worklist.push_back(NewV);
} else {
MergeGepUse(*Use);
// merge any GEP users of the untranslated bitcast
addUsersToWorklist(V);
}
} else if (dyn_cast<GEPOperator>(*Use)) {
if (GEPOperator *prevGEP = dyn_cast<GEPOperator>(V)) {
// merge the 2 GEPs
Value *newGEP = MergeGEP(prevGEP, GEP);
// Don't need to replace when GEP is updated in place
if (newGEP != GEP) {
GEP->replaceAllUsesWith(newGEP);
GEP->eraseFromParent();
} else if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
if (GEPOperator *prevGEP = dyn_cast<GEPOperator>(GEP->getPointerOperand())) {
// merge the 2 GEPs, returns nullptr if couldn't merge
if (Value *newGEP = MergeGEP(prevGEP, GEP)) {
worklist.push_back(newGEP);
// delete prevGEP if no more users
if (prevGEP->user_empty() && isa<GetElementPtrInst>(prevGEP))
cast<GetElementPtrInst>(prevGEP)->eraseFromParent();
}
MergeGepUse(newGEP);
} else {
MergeGepUse(*Use);
// nothing to merge yet, add GEP users
addUsersToWorklist(V);
}
}
}
if (V->user_empty()) {
// Only remove GEP here, root ptr will be removed by DCE.
if (GetElementPtrInst *I = dyn_cast<GetElementPtrInst>(V))
I->eraseFromParent();
}
}
template

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

@ -394,6 +394,7 @@ bool IsHLSLTriangleStreamType(clang::QualType type);
bool IsHLSLStreamOutputType(clang::QualType type);
bool IsHLSLResourceType(clang::QualType type);
bool IsHLSLBufferViewType(clang::QualType type);
bool IsHLSLStructuredBufferType(clang::QualType type);
bool IsHLSLNumericOrAggregateOfNumericType(clang::QualType type);
bool IsHLSLNumericUserDefinedType(clang::QualType type);
bool IsHLSLAggregateType(clang::QualType type);

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

@ -562,6 +562,18 @@ bool IsHLSLBufferViewType(clang::QualType type) {
return false;
}
bool IsHLSLStructuredBufferType(clang::QualType type) {
if (const RecordType *RT = type->getAs<RecordType>()) {
StringRef name = RT->getDecl()->getName();
if (name == "StructuredBuffer" || name == "RWStructuredBuffer")
return true;
if (name == "AppendStructuredBuffer" || name == "ConsumeStructuredBuffer")
return true;
}
return false;
}
bool IsHLSLSubobjectType(clang::QualType type) {
DXIL::SubobjectKind kind;
DXIL::HitGroupType hgType;

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

@ -204,7 +204,7 @@ private:
// Type annotation related.
unsigned ConstructStructAnnotation(DxilStructAnnotation *annotation,
DxilPayloadAnnotation* payloadAnnotation,
DxilPayloadAnnotation *payloadAnnotation,
const RecordDecl *RD,
DxilTypeSystem &dxilTypeSys);
unsigned AddTypeAnnotation(QualType Ty, DxilTypeSystem &dxilTypeSys,
@ -870,6 +870,10 @@ static void ConstructFieldInterpolation(DxilFieldAnnotation &fieldAnnotation,
static unsigned AlignBaseOffset(unsigned baseOffset, unsigned size, QualType Ty,
bool bDefaultRowMajor) {
// Do not align if resource, since resource isn't really here.
if (IsHLSLResourceType(Ty))
return baseOffset;
bool needNewAlign = Ty->isArrayType();
if (IsHLSLMatType(Ty)) {
@ -924,7 +928,7 @@ unsigned CGMSHLSLRuntime::ConstructStructAnnotation(DxilStructAnnotation *annota
const RecordDecl *RD,
DxilTypeSystem &dxilTypeSys) {
unsigned fieldIdx = 0;
unsigned offset = 0;
unsigned CBufferOffset = 0;
bool bDefaultRowMajor = m_pHLModule->GetHLOptions().bDefaultRowMajor;
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
@ -957,46 +961,47 @@ unsigned CGMSHLSLRuntime::ConstructStructAnnotation(DxilStructAnnotation *annota
QualType parentTy = QualType(BaseDecl->getTypeForDecl(), 0);
// Align offset.
offset = AlignBaseOffset(parentTy, offset, bDefaultRowMajor, CGM,
dataLayout);
unsigned CBufferOffset = offset;
unsigned arrayEltSize = 0;
// Process field to make sure the size of field is ready.
unsigned size =
AddTypeAnnotation(parentTy, dxilTypeSys, arrayEltSize);
unsigned arrayEltSize = 0;
unsigned size = AddTypeAnnotation(parentTy, dxilTypeSys, arrayEltSize);
// Update offset.
offset += size;
// Align offset.
if (size)
CBufferOffset = AlignBaseOffset(parentTy, CBufferOffset, bDefaultRowMajor, CGM,
dataLayout);
if (size > 0) {
llvm::StructType *baseType =
cast<llvm::StructType>(CGM.getTypes().ConvertType(parentTy));
DxilStructAnnotation *baseAnnotation =
dxilTypeSys.GetStructAnnotation(baseType);
if (size || (baseAnnotation && !baseAnnotation->IsEmptyStruct())) {
DxilFieldAnnotation &fieldAnnotation =
annotation->GetFieldAnnotation(fieldIdx++);
fieldAnnotation.SetCBufferOffset(CBufferOffset);
fieldAnnotation.SetFieldName(BaseDecl->getNameAsString());
}
// Update offset.
CBufferOffset += size;
}
}
}
unsigned CBufferSize = CBufferOffset;
for (auto fieldDecl : RD->fields()) {
std::string fieldSemName = "";
QualType fieldTy = fieldDecl->getType();
DXASSERT(!fieldDecl->isBitField(), "We should have already ensured we have no bitfields.");
// Align offset.
offset = AlignBaseOffset(fieldTy, offset, bDefaultRowMajor, CGM, dataLayout);
unsigned CBufferOffset = offset;
DxilFieldAnnotation &fieldAnnotation = annotation->GetFieldAnnotation(fieldIdx++);
ConstructFieldAttributedAnnotation(fieldAnnotation, fieldTy, bDefaultRowMajor);
// Try to get info from fieldDecl.
const hlsl::ConstantPacking *packOffset = nullptr;
for (const hlsl::UnusualAnnotation *it :
fieldDecl->getUnusualAnnotations()) {
switch (it->getKind()) {
@ -1005,9 +1010,9 @@ unsigned CGMSHLSLRuntime::ConstructStructAnnotation(DxilStructAnnotation *annota
fieldSemName = sd->SemanticName;
} break;
case hlsl::UnusualAnnotation::UA_ConstantPacking: {
const hlsl::ConstantPacking *cp = cast<hlsl::ConstantPacking>(it);
CBufferOffset = cp->Subcomponent << 2;
CBufferOffset += cp->ComponentOffset;
packOffset = cast<hlsl::ConstantPacking>(it);
CBufferOffset = packOffset->Subcomponent << 2;
CBufferOffset += packOffset->ComponentOffset;
// Change to byte.
CBufferOffset <<= 2;
} break;
@ -1041,13 +1046,25 @@ unsigned CGMSHLSLRuntime::ConstructStructAnnotation(DxilStructAnnotation *annota
}
}
unsigned arrayEltSize = 0;
// Process field to make sure the size of field is ready.
unsigned arrayEltSize = 0;
unsigned size = AddTypeAnnotation(fieldDecl->getType(), dxilTypeSys, arrayEltSize);
// Update offset.
offset += size;
// Align offset.
if (size) {
unsigned offset = AlignBaseOffset(fieldTy, CBufferOffset, bDefaultRowMajor, CGM, dataLayout);
if (packOffset && CBufferOffset != offset) {
// custom offset has an alignment problem, or this code does
DiagnosticsEngine &Diags = CGM.getDiags();
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error,
"custom offset mis-aligned.");
Diags.Report(packOffset->Loc, DiagID);
return 0;
}
CBufferOffset = offset;
}
ConstructFieldInterpolation(fieldAnnotation, fieldDecl);
if (fieldDecl->hasAttr<HLSLPreciseAttr>())
fieldAnnotation.SetPrecise();
@ -1060,13 +1077,15 @@ unsigned CGMSHLSLRuntime::ConstructStructAnnotation(DxilStructAnnotation *annota
if (m_PreciseOutputSet.count(StringRef(fieldSemName).lower()))
fieldAnnotation.SetPrecise();
}
// Update offset.
CBufferSize = std::max(CBufferSize, CBufferOffset + size);
CBufferOffset = CBufferSize;
}
annotation->SetCBufferSize(offset);
if (offset == 0) {
annotation->MarkEmptyStruct();
}
return offset;
annotation->SetCBufferSize(CBufferSize);
dxilTypeSys.FinishStructAnnotation(*annotation);
return CBufferSize;
}
static bool IsElementInputOutputType(QualType Ty) {
@ -1147,6 +1166,9 @@ static bool ValidatePayloadDecl(const RecordDecl *Decl,
unsigned CGMSHLSLRuntime::AddTypeAnnotation(QualType Ty,
DxilTypeSystem &dxilTypeSys,
unsigned &arrayEltSize) {
if (Ty.isNull())
return 0;
QualType paramTy = Ty.getCanonicalType();
if (const ReferenceType *RefType = dyn_cast<ReferenceType>(paramTy))
paramTy = RefType->getPointeeType();
@ -1173,7 +1195,12 @@ unsigned CGMSHLSLRuntime::AddTypeAnnotation(QualType Ty,
else if (IsHLSLOutputPatchType(Ty))
return AddTypeAnnotation(GetHLSLOutputPatchElementType(Ty), dxilTypeSys,
arrayEltSize);
else if (const RecordType *RT = paramTy->getAsStructureType()) {
else if (!IsHLSLStructuredBufferType(Ty) && IsHLSLResourceType(Ty)) {
// Save result type info.
AddTypeAnnotation(GetHLSLResourceResultType(Ty), dxilTypeSys, arrayEltSize);
// Resources don't count towards cbuffer size.
return 0;
} else if (const RecordType *RT = paramTy->getAsStructureType()) {
RecordDecl *RD = RT->getDecl();
llvm::StructType *ST = CGM.getTypes().ConvertRecordDeclType(RD);
// Skip if already created.
@ -1186,7 +1213,9 @@ unsigned CGMSHLSLRuntime::AddTypeAnnotation(QualType Ty,
DxilPayloadAnnotation *payloadAnnotation = nullptr;
if (ValidatePayloadDecl(RT->getDecl(), *m_pHLModule->GetShaderModel(), CGM.getDiags(), CGM.getCodeGenOpts()))
payloadAnnotation = dxilTypeSys.AddPayloadAnnotation(ST);
return ConstructStructAnnotation(annotation, payloadAnnotation, RD, dxilTypeSys);
unsigned size = ConstructStructAnnotation(annotation, payloadAnnotation, RD, dxilTypeSys);
// Resources don't count towards cbuffer size.
return IsHLSLResourceType(Ty) ? 0 : size;
} else if (const RecordType *RT = dyn_cast<RecordType>(paramTy)) {
// For this pointer.
RecordDecl *RD = RT->getDecl();
@ -1202,11 +1231,6 @@ unsigned CGMSHLSLRuntime::AddTypeAnnotation(QualType Ty,
if (ValidatePayloadDecl(RT->getDecl(), *m_pHLModule->GetShaderModel(), CGM.getDiags(), CGM.getCodeGenOpts()))
payloadAnnotation = dxilTypeSys.AddPayloadAnnotation(ST);
return ConstructStructAnnotation(annotation, payloadAnnotation, RD, dxilTypeSys);
} else if (IsHLSLResourceType(Ty)) {
// Save result type info.
AddTypeAnnotation(GetHLSLResourceResultType(Ty), dxilTypeSys, arrayEltSize);
// Resource don't count for cbuffer size.
return 0;
} else if (IsStringType(Ty)) {
// string won't be included in cbuffer
return 0;
@ -2298,20 +2322,24 @@ void CGMSHLSLRuntime::AddHLSLFunctionInfo(Function *F, const FunctionDecl *FD) {
return;
// Type annotation for parameters and return type.
DxilTypeSystem &dxilTypeSys = m_pHLModule->GetTypeSystem();
unsigned arrayEltSize = 0;
AddTypeAnnotation(FD->getReturnType(), dxilTypeSys, arrayEltSize);
{
DxilTypeSystem &dxilTypeSys = m_pHLModule->GetTypeSystem();
unsigned arrayEltSize = 0;
AddTypeAnnotation(FD->getReturnType(), dxilTypeSys, arrayEltSize);
// Type annotation for this pointer.
if (const CXXMethodDecl *MFD = dyn_cast<CXXMethodDecl>(FD)) {
const CXXRecordDecl *RD = MFD->getParent();
QualType Ty = CGM.getContext().getTypeDeclType(RD);
AddTypeAnnotation(Ty, dxilTypeSys, arrayEltSize);
}
// Type annotation for this pointer.
if (const CXXMethodDecl *MFD = dyn_cast<CXXMethodDecl>(FD)) {
const CXXRecordDecl *RD = MFD->getParent();
QualType Ty = CGM.getContext().getTypeDeclType(RD);
AddTypeAnnotation(Ty, dxilTypeSys, arrayEltSize);
}
for (const ValueDecl *param : FD->params()) {
QualType Ty = param->getType();
AddTypeAnnotation(Ty, dxilTypeSys, arrayEltSize);
for (const ValueDecl *param : FD->params()) {
QualType Ty = param->getType();
AddTypeAnnotation(Ty, dxilTypeSys, arrayEltSize);
}
dxilTypeSys.FinishFunctionAnnotation(*FuncAnnotation);
}
// clear isExportedEntry if not exporting entry

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

@ -1984,6 +1984,10 @@ unsigned AlignCBufferOffset(unsigned offset, unsigned size, llvm::Type *Ty,
bool bRowMajor, bool bMinPrecMode,
bool &bCurRowIsMinPrec) {
DXASSERT(!(offset & 1), "otherwise we have an invalid offset.");
// resources, empty structure, or structures with only resources have
// zero size, and need no alignment.
if (size == 0)
return offset;
bool bNeedNewRow = Ty->isArrayTy();
// In min-precision mode, a new row is needed when
// going into or out of min-precision component type.

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

@ -93,8 +93,6 @@
// CHECK: ; RWTex4 UAV f32 2d U2 u17 6
// CHECK: ; RWTex1 UAV f32 2d U3 u0 4
// CHECK: %struct.Resources = type { %"class.Texture2D<float>", %"class.Texture2D<vector<float, 4> >", %"class.Texture2D<float>", %"class.Texture2D<vector<float, 4> >", %"class.RWTexture2D<vector<float, 4> >", %"class.RWTexture2D<vector<float, 4> >", %"class.RWTexture2D<vector<float, 4> >", %"class.RWTexture2D<vector<float, 4> >", %struct.SamplerComparisonState, %struct.SamplerState, %struct.SamplerComparisonState, %struct.SamplerState, <4 x float> }
// CHK60: %[[RWTex2:.*]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 1, i32 0, i32 7, i1 false)
// CHK60: %[[MyTB:.*]] = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 4, i32 11, i1 false)

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

@ -1,24 +1,61 @@
// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
// CHECK:tx0.s sampler NA NA S0 s0 1
// CHECK:tx1.s sampler NA NA S1 s1 1
// CHECK:tx0.t texture f32 2d T0 t0 1
// CHECK:tx1.t texture f32 2d T1 t1 1
// Make sure structures with only resources have resource fields removed,
// are considered empty, take no space in CBuffer, and do not force alignment.
// CHECK: cbuffer $Globals
// CHECK: struct hostlayout.$Globals
// CHECK: float h; ; Offset: 0
// CHECK: struct hostlayout.struct.LegacyTex
// CHECK: /* empty struct */
// CHECK: } tx1; ; Offset: 4
// CHECK: float i; ; Offset: 4
// CHECK: } $Globals; ; Offset: 0 Size: 8
// CHECK: cbuffer CB0
// CHECK: struct hostlayout.CB0
// CHECK: float f; ; Offset: 0
// CHECK: struct hostlayout.struct.LegacyTex
// CHECK: /* empty struct */
// CHECK: } tx0; ; Offset: 4
// CHECK: float g; ; Offset: 4
// CHECK: } CB0; ; Offset: 0 Size: 8
// CHECK: $Globals cbuffer NA NA CB0 cb0 1
// CHECK: CB0 cbuffer NA NA CB1 cb1 1
// TODO: Preserve delcaration order when allocating resources from structs
// CHECK-DAG: tx0.s sampler NA NA S{{.}} s{{.}} 1
// CHECK-DAG: tx1.s sampler NA NA S{{.}} s{{.}} 1
// CHECK-DAG: b0 texture f32 buf T{{.}} t{{.}} 1
// CHECK-DAG: b1 texture f32 buf T{{.}} t{{.}} 1
// CHECK-DAG: tx0.t texture f32 2d T{{.}} t{{.}} 1
// CHECK-DAG: tx1.t texture f32 2d T{{.}} t{{.}} 1
// bound the check-dags
// CHECK: define void @main() {
struct LegacyTex
{
Texture2D t;
SamplerState s;
Texture2D t;
SamplerState s;
};
LegacyTex tx0;
LegacyTex tx1;
cbuffer CB0 {
float f; // CB0[0].x
LegacyTex tx0; // t0, s0
float g; // CB0[0].y
}
Buffer<float4> b0; // t1
float h; // $Globals[0].x
LegacyTex tx1; // t2, s1
float i; // $Globals[0].y
Buffer<float4> b1; // t3
float4 tex2D(LegacyTex tx, float2 uv)
{
return tx.t.Sample(tx.s,uv);
return tx.t.Sample(tx.s,uv);
}
float4 main(float2 uv:UV) : SV_Target
{
return tex2D(tx0,uv) + tex2D(tx1,uv);
}
return h * b0[(uint)uv.y] * tex2D(tx1,uv) + b1[(uint)uv.x] * tex2D(tx0,uv) * f + g + i;
}

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

@ -0,0 +1,61 @@
// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
// Make sure structures with resources have resource fields removed.
// CHECK: cbuffer $Globals
// CHECK: struct hostlayout.$Globals
// CHECK: float h; ; Offset: 0
// CHECK: struct hostlayout.struct.LegacyTex
// CHECK: float f; ; Offset: 16
// CHECK: } tx1; ; Offset: 16
// CHECK: float i; ; Offset: 20
// CHECK: } $Globals; ; Offset: 0 Size: 24
// CHECK: cbuffer CB0
// CHECK: struct hostlayout.CB0
// CHECK: float f; ; Offset: 0
// CHECK: struct hostlayout.struct.LegacyTex
// CHECK: float f; ; Offset: 16
// CHECK: } tx0; ; Offset: 16
// CHECK: float g; ; Offset: 20
// CHECK: } CB0; ; Offset: 0 Size: 24
// CHECK: $Globals cbuffer NA NA CB0 cb0 1
// CHECK: CB0 cbuffer NA NA CB1 cb1 1
// TODO: Preserve delcaration order when allocating resources from structs
// CHECK-DAG: tx0.s sampler NA NA S{{.}} s{{.}} 1
// CHECK-DAG: tx1.s sampler NA NA S{{.}} s{{.}} 1
// CHECK-DAG: b0 texture f32 buf T{{.}} t{{.}} 1
// CHECK-DAG: b1 texture f32 buf T{{.}} t{{.}} 1
// CHECK-DAG: tx0.t texture f32 2d T{{.}} t{{.}} 1
// CHECK-DAG: tx1.t texture f32 2d T{{.}} t{{.}} 1
// bound the check-dags
// CHECK: define void @main() {
struct LegacyTex
{
Texture2D t;
float f;
SamplerState s;
};
cbuffer CB0 {
float f; // CB0[0].x
LegacyTex tx0; // t0, s0, CB0[1].x
float g; // CB0[2].x
}
Buffer<float4> b0; // t1
float h; // $Globals[0].x
LegacyTex tx1; // t2, s1, $Globals[1].x
float i; // $Globals[2].x
Buffer<float4> b1; // t3
float4 tex2D(LegacyTex tx, float2 uv)
{
return tx.t.Sample(tx.s,uv) * tx.f;
}
float4 main(float2 uv:UV) : SV_Target
{
return h * b0[(uint)uv.y] * tex2D(tx1,uv) + b1[(uint)uv.x] * tex2D(tx0,uv) * f + g * i;
}

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

@ -1,5 +1,6 @@
// RUN: %dxc -E main -T cs_6_0 %s | FileCheck %s
// RUN: %dxc -E main -T cs_6_0 -fcgl %s | FileCheck %s
// Check unlowered type
// CHECK: %"class.StructuredBuffer<matrix<float, 4, 4> >" = type { %class.matrix.float.4.4 }
StructuredBuffer<matrix> buf1;

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

@ -1,6 +1,5 @@
// RUN: %dxc -auto-binding-space 13 -T lib_6_3 -export-shaders-only %s | FileCheck %s
// CHECK: class.Buffer
// CHECK-NOT: unused
// CHECK-NOT: @"\01?HSPerPatchFunc1@@YA?AUHSPerPatchData@@V?$InputPatch@UPSSceneIn@@$0BA@@@@Z"
// CHECK: define void @"\01?HSPerPatchFunc2

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

@ -1,7 +1,6 @@
// RUN: %dxc -auto-binding-space 13 -T lib_6_3 -export-shaders-only %s | FileCheck %s
// CHECK: %struct.Payload
// CHECK: class.Buffer
// CHECK-NOT: unused
// CHECK: define void @"\01?AnyHit
// CHECK: define void @"\01?Callable

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

@ -0,0 +1,47 @@
// RUN: %dxc -T lib_6_3 -Od %s | FileCheck %s
// Verifies packoffset of struct with multiple levels of inheritance
// CHECK: } cb_pld; ; Offset: 32
// CHECK: float f; ; Offset: 4
// CHECK: } CB; ; Offset: 0 Size: 72
// Make sure bitcast to base for `this` as part of the method call gets folded into GEP on -Od
// CHECK: define void [[raygen1:@"\\01\?raygen1@[^\"]+"]]() #0 {
// CHECK-NOT: bitcast
// CHECK: ret void
struct SuperBasePayload {
float g;
bool DoInner() { return g < 0; }
};
struct BasePayload : SuperBasePayload {
float f;
bool DoSomething() { return f < 0 && DoInner(); }
};
struct MyPayload : BasePayload {
int i;
float4 color;
uint2 pos;
};
RaytracingAccelerationStructure RTAS : register(t5);
RWByteAddressBuffer BAB : register(u0) ;
cbuffer CB : register(b0) {
MyPayload cb_pld : packoffset(c2.x);
float f : packoffset(c0.y);
}
[shader("raygeneration")]
void raygen1()
{
MyPayload p = cb_pld;
p.pos = DispatchRaysIndex();
float3 origin = {0, 0, 0};
float3 dir = normalize(float3(p.pos / (float)DispatchRaysDimensions(), 1));
RayDesc ray = { origin, 0.125, dir, 128.0};
TraceRay(RTAS, RAY_FLAG_NONE, 0, 0, 1, 0, ray, p);
BAB.Store(p.pos.x + p.pos.y * DispatchRaysDimensions().x, p.DoSomething());
}

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

@ -204,7 +204,13 @@ public:
std::string baseName(baseDesc.Name);
if (baseName.compare(0, 4, "half", 4) == 0)
baseName = baseName.replace(0, 4, "float", 5);
VERIFY_ARE_EQUAL_STR(testDesc.Name, baseName.c_str());
// For anonymous structures, fxc uses "scope::<unnamed>",
// dxc uses "anon", and may have additional ".#" for name disambiguation.
// Just skip name check if struct is unnamed according to fxc.
if (baseName.find("<unnamed>") == std::string::npos) {
VERIFY_ARE_EQUAL_STR(testDesc.Name, baseName.c_str());
}
for (UINT i = 0; i < baseDesc.Members; ++i) {
ID3D12ShaderReflectionType* testMemberType = pTest->GetMemberTypeByIndex(i);
@ -1800,6 +1806,7 @@ TEST_F(DxilContainerTest, ReflectionMatchesDXBC_CheckIn) {
ReflectionTest(hlsl_test::GetPathToHlslDataFile(L"..\\HLSLFileCheck\\d3dreflect\\tbuffer.hlsl").c_str(), false,
D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY);
ReflectionTest(hlsl_test::GetPathToHlslDataFile(L"..\\HLSLFileCheck\\d3dreflect\\texture2dms.hlsl").c_str(), false);
ReflectionTest(hlsl_test::GetPathToHlslDataFile(L"..\\HLSLFileCheck\\hlsl\\objects\\StructuredBuffer\\layout.hlsl").c_str(), false);
}
TEST_F(DxilContainerTest, ReflectionMatchesDXBC_Full) {

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

@ -489,9 +489,22 @@ public:
if (bRegex) {
llvm::Regex RE(pLookFor);
std::string reErrors;
if (!RE.isValid(reErrors)) {
WEX::Logging::Log::Comment(WEX::Common::String().Format(
L"Regex errors:\r\n%.*S\r\nWhile compiling expression '%S'",
(unsigned)reErrors.size(), reErrors.data(),
pLookFor));
}
VERIFY_IS_TRUE(RE.isValid(reErrors));
std::string replaced = RE.sub(pReplacement, disassembly, &reErrors);
if (!bOptional) {
if (!reErrors.empty()) {
WEX::Logging::Log::Comment(WEX::Common::String().Format(
L"Regex errors:\r\n%.*S\r\nWhile searching for '%S' in text:\r\n%.*S",
(unsigned)reErrors.size(), reErrors.data(),
pLookFor,
(unsigned)disassembly.size(), disassembly.data()));
}
VERIFY_ARE_NOT_EQUAL(disassembly, replaced);
VERIFY_IS_TRUE(reErrors.empty());
}
@ -510,6 +523,12 @@ public:
pos += replaceLen;
}
if (!bOptional) {
if (!found) {
WEX::Logging::Log::Comment(WEX::Common::String().Format(
L"String not found: '%S' in text:\r\n%.*S",
pLookFor,
(unsigned)disassembly.size(), disassembly.data()));
}
VERIFY_IS_TRUE(found);
}
}
@ -719,17 +738,17 @@ TEST_F(ValidationTest, BarrierFail) {
{"dx.op.barrier(i32 80, i32 8)",
"dx.op.barrier(i32 80, i32 9)",
"dx.op.barrier(i32 80, i32 11)",
"%\"class.RWStructuredBuffer<matrix<float, 2, 2> >\" = type { %class.matrix.float.2.2 }\n",
"%\"hostlayout.class.RWStructuredBuffer<matrix<float, 2, 2> >\" = type { [2 x <2 x float>] }\n",
"call i32 @dx.op.flattenedThreadIdInGroup.i32(i32 96)",
},
{"dx.op.barrier(i32 80, i32 15)",
"dx.op.barrier(i32 80, i32 0)",
"dx.op.barrier(i32 80, i32 %rem)",
"%\"class.RWStructuredBuffer<matrix<float, 2, 2> >\" = type { %class.matrix.float.2.2 }\n"
"@dx.typevar.8 = external addrspace(1) constant %\"class.RWStructuredBuffer<matrix<float, 2, 2> >\"\n"
"%\"hostlayout.class.RWStructuredBuffer<matrix<float, 2, 2> >\" = type { [2 x <2 x float>] }\n"
"@dx.typevar.8 = external addrspace(1) constant %\"hostlayout.class.RWStructuredBuffer<matrix<float, 2, 2> >\"\n"
"@\"internalGV\" = internal global [64 x <4 x float>] undef\n",
"call i32 @dx.op.flattenedThreadIdInGroup.i32(i32 96)\n"
"%load = load %\"class.RWStructuredBuffer<matrix<float, 2, 2> >\", %\"class.RWStructuredBuffer<matrix<float, 2, 2> >\" addrspace(1)* @dx.typevar.8",
"%load = load %\"hostlayout.class.RWStructuredBuffer<matrix<float, 2, 2> >\", %\"hostlayout.class.RWStructuredBuffer<matrix<float, 2, 2> >\" addrspace(1)* @dx.typevar.8",
},
{"Internal declaration 'internalGV' is unused",
"External declaration 'dx.typevar.8' is unused",
@ -3842,22 +3861,30 @@ TEST_F(ValidationTest, ValidatePrintfNotAllowed) {
TEST_F(ValidationTest, ValidateVersionNotAllowed) {
if (m_ver.SkipDxilVersion(1, 6)) return;
std::string maxValMinor = std::to_string(m_ver.m_ValMinor);
std::string higherValMinor = std::to_string(m_ver.m_ValMinor + 1);
std::string maxDxilMinor = std::to_string(m_ver.m_DxilMinor);
std::string higherDxilMinor = std::to_string(m_ver.m_DxilMinor + 1);
// When validator version is < dxil verrsion, compiler has a newer version
// than validator. We are checking the validator, so only use the validator
// version.
// This will also assume that the versions are tied together. This has always
// been the case, but it's not assumed that it has to be the case. If the
// versions diverged, it would be impossible to tell what DXIL version a
// validator supports just from the version returned in the IDxcVersion
// interface, without separate knowledge of the supported dxil version based
// on the validator version. If these versions must diverge in the future, we
// could rev the IDxcVersion interface to accomodate.
std::string maxMinor = std::to_string(m_ver.m_ValMinor);
std::string higherMinor = std::to_string(m_ver.m_ValMinor + 1);
RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\basic.hlsl", "ps_6_0",
("= !{i32 1, i32 " + maxValMinor + "}").c_str(),
("= !{i32 1, i32 " + higherValMinor + "}").c_str(),
("error: Validator version in metadata (1." + higherValMinor + ") is not supported; maximum: (1." + maxValMinor + ")").c_str());
("= !{i32 1, i32 " + maxMinor + "}").c_str(),
("= !{i32 1, i32 " + higherMinor + "}").c_str(),
("error: Validator version in metadata (1." + higherMinor + ") is not supported; maximum: (1." + maxMinor + ")").c_str());
RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\basic.hlsl", "ps_6_0",
"= !{i32 1, i32 0}",
"= !{i32 1, i32 1}",
"error: Shader model requires Dxil Version 1.0");
RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\basic.hlsl", "ps_6_0",
"= !{i32 1, i32 0}",
("= !{i32 1, i32 " + higherDxilMinor + "}").c_str(),
("error: Dxil version in metadata (1." + higherDxilMinor + ") is not supported; maximum: (1." + maxDxilMinor + ")").c_str());
("= !{i32 1, i32 " + higherMinor + "}").c_str(),
("error: Dxil version in metadata (1." + higherMinor + ") is not supported; maximum: (1." + maxMinor + ")").c_str());
}
TEST_F(ValidationTest, CreateHandleNotAllowedSM66) {