DirectXShaderCompiler/lib/DXIL/DxilTypeSystem.cpp

512 строки
18 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// //
// DxilTypeSystem.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. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "dxc/DXIL/DxilTypeSystem.h"
#include "dxc/DXIL/DxilModule.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/WinFunctions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using std::unique_ptr;
using std::string;
using std::vector;
using std::map;
namespace hlsl {
//------------------------------------------------------------------------------
//
// DxilMatrixAnnotation class methods.
//
DxilMatrixAnnotation::DxilMatrixAnnotation()
: Rows(0)
, Cols(0)
, Orientation(MatrixOrientation::Undefined) {
}
//------------------------------------------------------------------------------
//
// DxilFieldAnnotation class methods.
//
DxilFieldAnnotation::DxilFieldAnnotation()
: m_bPrecise(false)
, m_ResourceAttribute(nullptr)
, m_CBufferOffset(UINT_MAX) {
}
bool DxilFieldAnnotation::IsPrecise() const { return m_bPrecise; }
void DxilFieldAnnotation::SetPrecise(bool b) { m_bPrecise = b; }
bool DxilFieldAnnotation::HasMatrixAnnotation() const { return m_Matrix.Cols != 0; }
const DxilMatrixAnnotation &DxilFieldAnnotation::GetMatrixAnnotation() const { return m_Matrix; }
void DxilFieldAnnotation::SetMatrixAnnotation(const DxilMatrixAnnotation &MA) { m_Matrix = MA; }
bool DxilFieldAnnotation::HasResourceAttribute() const {
return m_ResourceAttribute;
}
llvm::MDNode *DxilFieldAnnotation::GetResourceAttribute() const {
return m_ResourceAttribute;
}
void DxilFieldAnnotation::SetResourceAttribute(llvm::MDNode *MD) {
m_ResourceAttribute = MD;
}
bool DxilFieldAnnotation::HasCBufferOffset() const { return m_CBufferOffset != UINT_MAX; }
unsigned DxilFieldAnnotation::GetCBufferOffset() const { return m_CBufferOffset; }
void DxilFieldAnnotation::SetCBufferOffset(unsigned Offset) { m_CBufferOffset = Offset; }
bool DxilFieldAnnotation::HasCompType() const { return m_CompType.GetKind() != CompType::Kind::Invalid; }
const CompType &DxilFieldAnnotation::GetCompType() const { return m_CompType; }
void DxilFieldAnnotation::SetCompType(CompType::Kind kind) { m_CompType = CompType(kind); }
bool DxilFieldAnnotation::HasSemanticString() const { return !m_Semantic.empty(); }
const std::string &DxilFieldAnnotation::GetSemanticString() const { return m_Semantic; }
llvm::StringRef DxilFieldAnnotation::GetSemanticStringRef() const { return llvm::StringRef(m_Semantic); }
void DxilFieldAnnotation::SetSemanticString(const std::string &SemString) { m_Semantic = SemString; }
bool DxilFieldAnnotation::HasInterpolationMode() const { return !m_InterpMode.IsUndefined(); }
const InterpolationMode &DxilFieldAnnotation::GetInterpolationMode() const { return m_InterpMode; }
void DxilFieldAnnotation::SetInterpolationMode(const InterpolationMode &IM) { m_InterpMode = IM; }
bool DxilFieldAnnotation::HasFieldName() const { return !m_FieldName.empty(); }
const std::string &DxilFieldAnnotation::GetFieldName() const { return m_FieldName; }
void DxilFieldAnnotation::SetFieldName(const std::string &FieldName) { m_FieldName = FieldName; }
//------------------------------------------------------------------------------
//
// DxilStructAnnotation class methods.
//
unsigned DxilStructAnnotation::GetNumFields() const {
return (unsigned)m_FieldAnnotations.size();
}
DxilFieldAnnotation &DxilStructAnnotation::GetFieldAnnotation(unsigned FieldIdx) {
return m_FieldAnnotations[FieldIdx];
}
const DxilFieldAnnotation &DxilStructAnnotation::GetFieldAnnotation(unsigned FieldIdx) const {
return m_FieldAnnotations[FieldIdx];
}
const StructType *DxilStructAnnotation::GetStructType() const {
return m_pStructType;
}
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(); }
//------------------------------------------------------------------------------
//
// DxilParameterAnnotation class methods.
//
DxilParameterAnnotation::DxilParameterAnnotation()
: DxilFieldAnnotation(), m_inputQual(DxilParamInputQual::In) {
}
DxilParamInputQual DxilParameterAnnotation::GetParamInputQual() const {
return m_inputQual;
}
void DxilParameterAnnotation::SetParamInputQual(DxilParamInputQual qual) {
m_inputQual = qual;
}
const std::vector<unsigned> &DxilParameterAnnotation::GetSemanticIndexVec() const {
return m_semanticIndex;
}
void DxilParameterAnnotation::SetSemanticIndexVec(const std::vector<unsigned> &Vec) {
m_semanticIndex = Vec;
}
void DxilParameterAnnotation::AppendSemanticIndex(unsigned SemIdx) {
m_semanticIndex.emplace_back(SemIdx);
}
//------------------------------------------------------------------------------
//
// DxilFunctionAnnotation class methods.
//
unsigned DxilFunctionAnnotation::GetNumParameters() const {
return (unsigned)m_parameterAnnotations.size();
}
DxilParameterAnnotation &DxilFunctionAnnotation::GetParameterAnnotation(unsigned ParamIdx) {
return m_parameterAnnotations[ParamIdx];
}
const DxilParameterAnnotation &DxilFunctionAnnotation::GetParameterAnnotation(unsigned ParamIdx) const {
return m_parameterAnnotations[ParamIdx];
}
DxilParameterAnnotation &DxilFunctionAnnotation::GetRetTypeAnnotation() {
return m_retTypeAnnotation;
}
const DxilParameterAnnotation &DxilFunctionAnnotation::GetRetTypeAnnotation() const {
return m_retTypeAnnotation;
}
const Function *DxilFunctionAnnotation::GetFunction() const {
return m_pFunction;
}
//------------------------------------------------------------------------------
//
// DxilStructAnnotationSystem class methods.
//
DxilTypeSystem::DxilTypeSystem(Module *pModule)
: m_pModule(pModule),
m_LowPrecisionMode(DXIL::LowPrecisionMode::Undefined) {}
DxilStructAnnotation *DxilTypeSystem::AddStructAnnotation(const StructType *pStructType) {
DXASSERT_NOMSG(m_StructAnnotations.find(pStructType) == m_StructAnnotations.end());
DxilStructAnnotation *pA = new DxilStructAnnotation();
m_StructAnnotations[pStructType] = unique_ptr<DxilStructAnnotation>(pA);
pA->m_pStructType = pStructType;
pA->m_FieldAnnotations.resize(pStructType->getNumElements());
return pA;
}
DxilStructAnnotation *DxilTypeSystem::GetStructAnnotation(const StructType *pStructType) {
auto it = m_StructAnnotations.find(pStructType);
if (it != m_StructAnnotations.end()) {
return it->second.get();
} else {
return nullptr;
}
}
const DxilStructAnnotation *
DxilTypeSystem::GetStructAnnotation(const StructType *pStructType) const {
auto it = m_StructAnnotations.find(pStructType);
if (it != m_StructAnnotations.end()) {
return it->second.get();
} else {
return nullptr;
}
}
void DxilTypeSystem::EraseStructAnnotation(const StructType *pStructType) {
DXASSERT_NOMSG(m_StructAnnotations.count(pStructType));
m_StructAnnotations.remove_if([pStructType](
const std::pair<const StructType *, std::unique_ptr<DxilStructAnnotation>>
&I) { return pStructType == I.first; });
}
DxilTypeSystem::StructAnnotationMap &DxilTypeSystem::GetStructAnnotationMap() {
return m_StructAnnotations;
}
DxilFunctionAnnotation *DxilTypeSystem::AddFunctionAnnotation(const Function *pFunction) {
DXASSERT_NOMSG(m_FunctionAnnotations.find(pFunction) == m_FunctionAnnotations.end());
DxilFunctionAnnotation *pA = new DxilFunctionAnnotation();
m_FunctionAnnotations[pFunction] = unique_ptr<DxilFunctionAnnotation>(pA);
pA->m_pFunction = pFunction;
pA->m_parameterAnnotations.resize(pFunction->getFunctionType()->getNumParams());
return pA;
}
DxilFunctionAnnotation *DxilTypeSystem::GetFunctionAnnotation(const Function *pFunction) {
auto it = m_FunctionAnnotations.find(pFunction);
if (it != m_FunctionAnnotations.end()) {
return it->second.get();
} else {
return nullptr;
}
}
const DxilFunctionAnnotation *
DxilTypeSystem::GetFunctionAnnotation(const Function *pFunction) const {
auto it = m_FunctionAnnotations.find(pFunction);
if (it != m_FunctionAnnotations.end()) {
return it->second.get();
} else {
return nullptr;
}
}
void DxilTypeSystem::EraseFunctionAnnotation(const Function *pFunction) {
DXASSERT_NOMSG(m_FunctionAnnotations.count(pFunction));
m_FunctionAnnotations.remove_if([pFunction](
const std::pair<const Function *, std::unique_ptr<DxilFunctionAnnotation>>
&I) { return pFunction == I.first; });
}
DxilTypeSystem::FunctionAnnotationMap &DxilTypeSystem::GetFunctionAnnotationMap() {
return m_FunctionAnnotations;
}
StructType *DxilTypeSystem::GetSNormF32Type(unsigned NumComps) {
return GetNormFloatType(CompType::getSNormF32(), NumComps);
}
StructType *DxilTypeSystem::GetUNormF32Type(unsigned NumComps) {
return GetNormFloatType(CompType::getUNormF32(), NumComps);
}
StructType *DxilTypeSystem::GetNormFloatType(CompType CT, unsigned NumComps) {
Type *pCompType = CT.GetLLVMType(m_pModule->getContext());
DXASSERT_NOMSG(pCompType->isFloatTy());
Type *pFieldType = pCompType;
string TypeName;
raw_string_ostream NameStream(TypeName);
if (NumComps > 1) {
(NameStream << "dx.types." << NumComps << "x" << CT.GetName()).flush();
pFieldType = VectorType::get(pFieldType, NumComps);
} else {
(NameStream << "dx.types." << CT.GetName()).flush();
}
StructType *pStructType = m_pModule->getTypeByName(TypeName);
if (pStructType == nullptr) {
pStructType = StructType::create(m_pModule->getContext(), pFieldType, TypeName);
DxilStructAnnotation &TA = *AddStructAnnotation(pStructType);
DxilFieldAnnotation &FA = TA.GetFieldAnnotation(0);
FA.SetCompType(CT.GetKind());
DXASSERT_NOMSG(CT.IsSNorm() || CT.IsUNorm());
}
return pStructType;
}
void DxilTypeSystem::CopyTypeAnnotation(const llvm::Type *Ty,
const DxilTypeSystem &src) {
if (isa<PointerType>(Ty))
Ty = Ty->getPointerElementType();
while (isa<ArrayType>(Ty))
Ty = Ty->getArrayElementType();
// Only struct type has annotation.
if (!isa<StructType>(Ty))
return;
const StructType *ST = cast<StructType>(Ty);
// Already exist.
if (GetStructAnnotation(ST))
return;
if (const DxilStructAnnotation *annot = src.GetStructAnnotation(ST)) {
DxilStructAnnotation *dstAnnot = AddStructAnnotation(ST);
// Copy the annotation.
*dstAnnot = *annot;
// Copy field type annotations.
for (Type *Ty : ST->elements()) {
CopyTypeAnnotation(Ty, src);
}
}
}
void DxilTypeSystem::CopyFunctionAnnotation(const llvm::Function *pDstFunction,
const llvm::Function *pSrcFunction,
const DxilTypeSystem &src) {
const DxilFunctionAnnotation *annot = src.GetFunctionAnnotation(pSrcFunction);
// Don't have annotation.
if (!annot)
return;
// Already exist.
if (GetFunctionAnnotation(pDstFunction))
return;
DxilFunctionAnnotation *dstAnnot = AddFunctionAnnotation(pDstFunction);
// Copy the annotation.
*dstAnnot = *annot;
dstAnnot->m_pFunction = pDstFunction;
// Clone ret type annotation.
CopyTypeAnnotation(pDstFunction->getReturnType(), src);
// Clone param type annotations.
for (const Argument &arg : pDstFunction->args()) {
CopyTypeAnnotation(arg.getType(), src);
}
}
DXIL::SigPointKind SigPointFromInputQual(DxilParamInputQual Q, DXIL::ShaderKind SK, bool isPC) {
DXASSERT(Q != DxilParamInputQual::Inout, "Inout not expected for SigPointFromInputQual");
switch (SK) {
case DXIL::ShaderKind::Vertex:
switch (Q) {
case DxilParamInputQual::In:
return DXIL::SigPointKind::VSIn;
case DxilParamInputQual::Out:
return DXIL::SigPointKind::VSOut;
default:
break;
}
break;
case DXIL::ShaderKind::Hull:
switch (Q) {
case DxilParamInputQual::In:
if (isPC)
return DXIL::SigPointKind::PCIn;
else
return DXIL::SigPointKind::HSIn;
case DxilParamInputQual::Out:
if (isPC)
return DXIL::SigPointKind::PCOut;
else
return DXIL::SigPointKind::HSCPOut;
case DxilParamInputQual::InputPatch:
return DXIL::SigPointKind::HSCPIn;
case DxilParamInputQual::OutputPatch:
return DXIL::SigPointKind::HSCPOut;
default:
break;
}
break;
case DXIL::ShaderKind::Domain:
switch (Q) {
case DxilParamInputQual::In:
return DXIL::SigPointKind::DSIn;
case DxilParamInputQual::Out:
return DXIL::SigPointKind::DSOut;
case DxilParamInputQual::InputPatch:
case DxilParamInputQual::OutputPatch:
return DXIL::SigPointKind::DSCPIn;
default:
break;
}
break;
case DXIL::ShaderKind::Geometry:
switch (Q) {
case DxilParamInputQual::In:
return DXIL::SigPointKind::GSIn;
case DxilParamInputQual::InputPrimitive:
return DXIL::SigPointKind::GSVIn;
case DxilParamInputQual::OutStream0:
case DxilParamInputQual::OutStream1:
case DxilParamInputQual::OutStream2:
case DxilParamInputQual::OutStream3:
return DXIL::SigPointKind::GSOut;
default:
break;
}
break;
case DXIL::ShaderKind::Pixel:
switch (Q) {
case DxilParamInputQual::In:
return DXIL::SigPointKind::PSIn;
case DxilParamInputQual::Out:
return DXIL::SigPointKind::PSOut;
default:
break;
}
break;
case DXIL::ShaderKind::Compute:
switch (Q) {
case DxilParamInputQual::In:
return DXIL::SigPointKind::CSIn;
default:
break;
}
break;
default:
break;
}
return DXIL::SigPointKind::Invalid;
}
void RemapSemantic(llvm::StringRef &oldSemName, llvm::StringRef &oldSemFullName, const char *newSemName,
DxilParameterAnnotation &paramInfo, llvm::LLVMContext &Context) {
// format deprecation warning
Context.emitWarning(Twine("DX9-style semantic \"") + oldSemName + Twine("\" mapped to DX10 system semantic \"") + newSemName +
Twine("\" due to -Gec flag. This functionality is deprecated in newer language versions."));
// create new semantic name with the same index
std::string newSemNameStr(newSemName);
unsigned indexLen = oldSemFullName.size() - oldSemName.size();
if (indexLen > 0) {
newSemNameStr = newSemNameStr.append(oldSemFullName.data() + oldSemName.size(), indexLen);
}
paramInfo.SetSemanticString(newSemNameStr);
}
void RemapObsoleteSemantic(DxilParameterAnnotation &paramInfo, DXIL::SigPointKind sigPoint, llvm::LLVMContext &Context) {
DXASSERT(paramInfo.HasSemanticString(), "expected paramInfo with semantic");
//*ppWarningMsg = nullptr;
llvm::StringRef semFullName = paramInfo.GetSemanticStringRef();
llvm::StringRef semName;
unsigned semIndex;
Semantic::DecomposeNameAndIndex(semFullName, &semName, &semIndex);
if (sigPoint == DXIL::SigPointKind::PSOut) {
if (semName.size() == 5) {
if (_strnicmp(semName.data(), "COLOR", 5) == 0) {
RemapSemantic(semName, semFullName, "SV_Target", paramInfo, Context);
}
else if (_strnicmp(semName.data(), "DEPTH", 5) == 0) {
RemapSemantic(semName, semFullName, "SV_Depth", paramInfo, Context);
}
}
}
else if ((sigPoint == DXIL::SigPointKind::VSOut && semName.size() == 8 && _strnicmp(semName.data(), "POSITION", 8) == 0) ||
(sigPoint == DXIL::SigPointKind::PSIn && semName.size() == 4 && _strnicmp(semName.data(), "VPOS", 4) == 0)) {
RemapSemantic(semName, semFullName, "SV_Position", paramInfo, Context);
}
}
bool DxilTypeSystem::UseMinPrecision() {
return m_LowPrecisionMode == DXIL::LowPrecisionMode::UseMinPrecision;
}
void DxilTypeSystem::SetMinPrecision(bool bMinPrecision) {
DXIL::LowPrecisionMode mode =
bMinPrecision ? DXIL::LowPrecisionMode::UseMinPrecision
: DXIL::LowPrecisionMode::UseNativeLowPrecision;
DXASSERT((mode == m_LowPrecisionMode ||
m_LowPrecisionMode == DXIL::LowPrecisionMode::Undefined),
"LowPrecisionMode should only be set once.");
m_LowPrecisionMode = mode;
}
DxilStructTypeIterator::DxilStructTypeIterator(llvm::StructType *sTy, DxilStructAnnotation *sAnnotation,
unsigned idx)
: STy(sTy), SAnnotation(sAnnotation), index(idx) {
DXASSERT(
sTy->getNumElements() == sAnnotation->GetNumFields(),
"Otherwise the pairing of annotation and struct type does not match.");
}
// prefix
DxilStructTypeIterator &DxilStructTypeIterator::operator++() {
index++;
return *this;
}
// postfix
DxilStructTypeIterator DxilStructTypeIterator::operator++(int) {
DxilStructTypeIterator iter(STy, SAnnotation, index);
index++;
return iter;
}
bool DxilStructTypeIterator::operator==(DxilStructTypeIterator iter) {
return iter.STy == STy && iter.SAnnotation == SAnnotation &&
iter.index == index;
}
bool DxilStructTypeIterator::operator!=(DxilStructTypeIterator iter) { return !(operator==(iter)); }
std::pair<llvm::Type *, DxilFieldAnnotation *> DxilStructTypeIterator::operator*() {
return std::pair<llvm::Type *, DxilFieldAnnotation *>(
STy->getElementType(index), &SAnnotation->GetFieldAnnotation(index));
}
DxilStructTypeIterator begin(llvm::StructType *STy, DxilStructAnnotation *SAnno) {
return { STy, SAnno, 0 };
}
DxilStructTypeIterator end(llvm::StructType *STy, DxilStructAnnotation *SAnno) {
return { STy, SAnno, STy->getNumElements() };
}
} // namespace hlsl