Skip to content

Commit

Permalink
Report error for unsupported types of SV semantics (microsoft#3043)
Browse files Browse the repository at this point in the history
  • Loading branch information
vcsharma authored and bob80905 committed Apr 27, 2022
1 parent f2b05f0 commit cc65df2
Show file tree
Hide file tree
Showing 31 changed files with 915 additions and 35 deletions.
38 changes: 36 additions & 2 deletions include/dxc/DXIL/DxilSemantic.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#pragma once

#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Type.h"

#include "DxilConstants.h"
#include "DxilShaderModel.h"
Expand All @@ -23,6 +24,33 @@ class Semantic {
public:
using Kind = DXIL::SemanticKind;

enum class CompTy {
BoolTy = 1 << 0,
HalfTy = 1 << 1,
Int16Ty = 1 << 2,
FloatTy = 1 << 3,
Int32Ty = 1 << 4,
DoubleTy = 1 << 5,
Int64Ty = 1 << 6,
HalfOrFloatTy = HalfTy | FloatTy,
BoolOrInt32Ty = BoolTy | Int32Ty,
BoolOrInt16Or32Ty = BoolTy | Int16Ty | Int32Ty,
FloatOrInt32Ty = FloatTy | Int32Ty,
Int16Or32Ty = Int16Ty | Int32Ty,
AnyIntTy = BoolTy | Int16Ty | Int32Ty | Int64Ty,
AnyFloatTy = HalfTy | FloatTy | DoubleTy,
AnyTy = AnyIntTy | AnyFloatTy,
};

enum class SizeClass {
Unknown,
Scalar,
Vec2,
Vec3,
Vec4,
Other
};

static const int kUndefinedRow = -1;
static const int kUndefinedCol = -1;

Expand All @@ -41,13 +69,19 @@ class Semantic {
const char *GetName() const;
bool IsArbitrary() const;
bool IsInvalid() const;
bool IsSupportedType(llvm::Type *semTy) const;
CompTy GetCompType(llvm::Type* ty) const;
SizeClass GetCompCount(llvm::Type* ty) const;

private:
Kind m_Kind; // Semantic kind.
const char *m_pszName; // Canonical name (for system semantics).
const char *m_pszName; // Canonical name (for system semantics).
CompTy m_allowedTys; // Types allowed for the semantic
SizeClass m_minCompCount; // Minimum component count that is allowed for a semantic
SizeClass m_maxCompCount; // Maximum component count that is allowed for a semantic

Semantic() = delete;
Semantic(Kind Kind, const char *pszName);
Semantic(Kind Kind, const char *pszName, CompTy allowedTys, SizeClass minCompCount, SizeClass maxCompCount);

// Table of all semantic properties.
static const unsigned kNumSemanticRecords = (unsigned)Kind::Invalid + 1;
Expand Down
191 changes: 158 additions & 33 deletions lib/DXIL/DxilSemantic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "dxc/DXIL/DxilSemantic.h"
#include "dxc/DXIL/DxilSignature.h"
#include "dxc/DXIL/DxilShaderModel.h"
#include "dxc/DXIL/DxilUtil.h"
#include "dxc/Support/Global.h"

#include <string>
Expand All @@ -24,9 +25,15 @@ namespace hlsl {
// Semantic class methods.
//
Semantic::Semantic(Kind Kind,
const char *pszName)
const char *pszName,
CompTy allowedTys,
SizeClass minCompCount,
SizeClass maxCompCount)
: m_Kind(Kind)
, m_pszName(pszName)
, m_allowedTys(allowedTys)
, m_minCompCount(minCompCount)
, m_maxCompCount(maxCompCount)
{
}

Expand Down Expand Up @@ -113,41 +120,159 @@ bool Semantic::IsInvalid() const {
return m_Kind == Kind::Invalid;
}

Semantic::SizeClass Semantic::GetCompCount(llvm::Type* ty) const {

if (!ty->isVectorTy() && !dxilutil::IsIntegerOrFloatingPointType(ty))
return SizeClass::Unknown;

if (ty->isVectorTy()) {
if (ty->getVectorNumElements() == 1) {
return SizeClass::Scalar;
}
else if (ty->getVectorNumElements() == 2) {
return SizeClass::Vec2;
}
else if (ty->getVectorNumElements() == 3) {
return SizeClass::Vec3;
}
else if (ty->getVectorNumElements() == 4) {
return SizeClass::Vec4;
}
else {
DXASSERT(false, "Unexpected number of vector elements.");
return SizeClass::Unknown;
}
}

return SizeClass::Scalar;
}

Semantic::CompTy Semantic::GetCompType(llvm::Type* ty) const {

if (!ty->isVectorTy() && !dxilutil::IsIntegerOrFloatingPointType(ty))
return CompTy::AnyTy;

if (ty->isVectorTy())
ty = ty->getScalarType();

// must be an integer or a floating point type here
DXASSERT_NOMSG(dxilutil::IsIntegerOrFloatingPointType(ty));
if (ty->getScalarType()->isIntegerTy()) {
if (ty->getScalarSizeInBits() == 1) {
return CompTy::BoolTy;
} else if (ty->getScalarSizeInBits() == 16) {
return CompTy::Int16Ty;
} else if (ty->getScalarSizeInBits() == 32) {
return CompTy::Int32Ty;
} else {
return CompTy::Int64Ty;
}
} else {
if (ty->isHalfTy()) {
return CompTy::HalfTy;
} else if (ty->isFloatTy()) {
return CompTy::FloatTy;
} else {
DXASSERT_NOMSG(ty->isDoubleTy());
return CompTy::DoubleTy;
}
}
}

static bool IsScalarOrVectorTy(llvm::Type* ty) {
if (dxilutil::IsIntegerOrFloatingPointType(ty))
return true;
if (ty->isVectorTy() &&
dxilutil::IsIntegerOrFloatingPointType(ty->getVectorElementType()))
return true;
return false;
}

bool Semantic::IsSupportedType(llvm::Type* semTy) const {

if (m_Kind == Kind::Invalid)
return false;

// Skip type checking for Arbitrary kind
if (m_Kind == Kind::Arbitrary)
return true;

if (!IsScalarOrVectorTy(semTy)) {
// We only allow scalar or vector types as a valid semantic type except in some cases
// such as Clip/Cull or Tessfactor.
if (m_minCompCount == SizeClass::Other) {
if (semTy->isArrayTy()) {
semTy = semTy->getArrayElementType();
// TessFactor or InsideTessFactor must either be float[2] or float
if ((m_Kind == Kind::TessFactor ||
m_Kind == Kind::InsideTessFactor) &&
!dxilutil::IsIntegerOrFloatingPointType(semTy)) {
return false;
}
// Clip/Cull can be array of scalar or vector
if ((m_Kind == Kind::ClipDistance ||
m_Kind == Kind::CullDistance) &&
!IsScalarOrVectorTy(semTy)) {
return false;
}
}
else {
// Do not support other types such as matrix.
return false;
}
}
else {
return false;
}
}

if (((unsigned)m_allowedTys & (unsigned)GetCompType(semTy)) == 0)
return false;

// Skip type-shape validation for semantics marked as Other
if (m_minCompCount == SizeClass::Other)
return true;

SizeClass compSzClass = GetCompCount(semTy);
return compSzClass >= m_minCompCount &&
compSzClass <= m_maxCompCount;
}

typedef Semantic SP;
const Semantic Semantic::ms_SemanticTable[kNumSemanticRecords] = {
// Kind Name
SP(Kind::Arbitrary, nullptr),
SP(Kind::VertexID, "SV_VertexID"),
SP(Kind::InstanceID, "SV_InstanceID"),
SP(Kind::Position, "SV_Position"),
SP(Kind::RenderTargetArrayIndex,"SV_RenderTargetArrayIndex"),
SP(Kind::ViewPortArrayIndex, "SV_ViewportArrayIndex"),
SP(Kind::ClipDistance, "SV_ClipDistance"),
SP(Kind::CullDistance, "SV_CullDistance"),
SP(Kind::OutputControlPointID, "SV_OutputControlPointID"),
SP(Kind::DomainLocation, "SV_DomainLocation"),
SP(Kind::PrimitiveID, "SV_PrimitiveID"),
SP(Kind::GSInstanceID, "SV_GSInstanceID"),
SP(Kind::SampleIndex, "SV_SampleIndex"),
SP(Kind::IsFrontFace, "SV_IsFrontFace"),
SP(Kind::Coverage, "SV_Coverage"),
SP(Kind::InnerCoverage, "SV_InnerCoverage"),
SP(Kind::Target, "SV_Target"),
SP(Kind::Depth, "SV_Depth"),
SP(Kind::DepthLessEqual, "SV_DepthLessEqual"),
SP(Kind::DepthGreaterEqual, "SV_DepthGreaterEqual"),
SP(Kind::StencilRef, "SV_StencilRef"),
SP(Kind::DispatchThreadID, "SV_DispatchThreadID"),
SP(Kind::GroupID, "SV_GroupID"),
SP(Kind::GroupIndex, "SV_GroupIndex"),
SP(Kind::GroupThreadID, "SV_GroupThreadID"),
SP(Kind::TessFactor, "SV_TessFactor"),
SP(Kind::InsideTessFactor, "SV_InsideTessFactor"),
SP(Kind::ViewID, "SV_ViewID"),
SP(Kind::Barycentrics, "SV_Barycentrics"),
SP(Kind::ShadingRate, "SV_ShadingRate"),
SP(Kind::CullPrimitive, "SV_CullPrimitive"),
SP(Kind::Invalid, nullptr),
SP(Kind::Arbitrary, nullptr, CompTy::AnyTy, SizeClass::Other, SizeClass::Other),
SP(Kind::VertexID, "SV_VertexID", CompTy::Int16Or32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::InstanceID, "SV_InstanceID", CompTy::Int16Or32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::Position, "SV_Position", CompTy::HalfOrFloatTy, SizeClass::Vec4, SizeClass::Vec4),
SP(Kind::RenderTargetArrayIndex,"SV_RenderTargetArrayIndex", CompTy::Int16Or32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::ViewPortArrayIndex, "SV_ViewportArrayIndex", CompTy::Int16Or32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::ClipDistance, "SV_ClipDistance", CompTy::HalfOrFloatTy, SizeClass::Other, SizeClass::Other),
SP(Kind::CullDistance, "SV_CullDistance", CompTy::HalfOrFloatTy, SizeClass::Other, SizeClass::Other),
SP(Kind::OutputControlPointID, "SV_OutputControlPointID", CompTy::Int32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::DomainLocation, "SV_DomainLocation", CompTy::FloatTy, SizeClass::Scalar, SizeClass::Vec3),
SP(Kind::PrimitiveID, "SV_PrimitiveID", CompTy::Int32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::GSInstanceID, "SV_GSInstanceID", CompTy::Int32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::SampleIndex, "SV_SampleIndex", CompTy::Int32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::IsFrontFace, "SV_IsFrontFace", CompTy::BoolOrInt32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::Coverage, "SV_Coverage", CompTy::Int32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::InnerCoverage, "SV_InnerCoverage", CompTy::Int32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::Target, "SV_Target", CompTy::AnyTy, SizeClass::Scalar, SizeClass::Vec4),
SP(Kind::Depth, "SV_Depth", CompTy::HalfOrFloatTy, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::DepthLessEqual, "SV_DepthLessEqual", CompTy::HalfOrFloatTy, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::DepthGreaterEqual, "SV_DepthGreaterEqual", CompTy::HalfOrFloatTy, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::StencilRef, "SV_StencilRef", CompTy::Int16Or32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::DispatchThreadID, "SV_DispatchThreadID", CompTy::Int16Or32Ty, SizeClass::Scalar, SizeClass::Vec3),
SP(Kind::GroupID, "SV_GroupID", CompTy::Int16Or32Ty, SizeClass::Scalar, SizeClass::Vec3),
SP(Kind::GroupIndex, "SV_GroupIndex", CompTy::Int16Or32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::GroupThreadID, "SV_GroupThreadID", CompTy::Int16Or32Ty, SizeClass::Scalar, SizeClass::Vec3),
SP(Kind::TessFactor, "SV_TessFactor", CompTy::HalfOrFloatTy, SizeClass::Other, SizeClass::Other),
SP(Kind::InsideTessFactor, "SV_InsideTessFactor", CompTy::HalfOrFloatTy, SizeClass::Other, SizeClass::Other),
SP(Kind::ViewID, "SV_ViewID", CompTy::Int32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::Barycentrics, "SV_Barycentrics", CompTy::HalfOrFloatTy, SizeClass::Vec3, SizeClass::Vec3),
SP(Kind::ShadingRate, "SV_ShadingRate", CompTy::Int16Or32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::CullPrimitive, "SV_CullPrimitive", CompTy::BoolOrInt16Or32Ty, SizeClass::Scalar, SizeClass::Scalar),
SP(Kind::Invalid, nullptr, CompTy::AnyTy, SizeClass::Other, SizeClass::Other),
};

} // namespace hlsl
50 changes: 50 additions & 0 deletions lib/HLSL/HLSignatureLower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,50 @@ void HLSignatureLower::GenerateDxilInputsOutputs(DXIL::SignatureKind SK) {
}
}

bool HLSignatureLower::ValidateSemanticType(llvm::Function* F) {
bool result = true;
DxilFunctionAnnotation* funcAnnotation = HLM.GetFunctionAnnotation(F);
if (!funcAnnotation) {
return result;
}
for (Argument& arg : F->args()) {
DxilParameterAnnotation &paramAnnotation =
funcAnnotation->GetParameterAnnotation(arg.getArgNo());
llvm::StringRef semanticStr = paramAnnotation.GetSemanticString();
if (semanticStr.empty()) {
continue;
}
unsigned index;
StringRef baseSemanticStr;
Semantic::DecomposeNameAndIndex(semanticStr, &baseSemanticStr, &index);
const Semantic* semantic = Semantic::GetByName(baseSemanticStr);
Type* argTy = arg.getType();

if (argTy->isPointerTy())
argTy = cast<PointerType>(argTy)->getPointerElementType();

if (argTy->isArrayTy()) {
// Array type for arguments with specific qualifiers are expected.
// In this case, we do validation on array's element type.
DxilParamInputQual inputQual = paramAnnotation.GetParamInputQual();
if (inputQual == DxilParamInputQual::InputPatch ||
inputQual == DxilParamInputQual::InputPrimitive ||
inputQual == DxilParamInputQual::OutIndices ||
inputQual == DxilParamInputQual::OutPrimitives ||
inputQual == DxilParamInputQual::OutputPatch ||
inputQual == DxilParamInputQual::OutVertices) {
argTy = cast<ArrayType>(argTy)->getArrayElementType();
}
}

if (!semantic->IsSupportedType(argTy)) {
dxilutil::EmitErrorOnFunction(F->getContext(), F, "invalid type used for \'"+ semanticStr.str() + "\' semantic.");
result = false;
}
}
return result;
}

void HLSignatureLower::GenerateDxilCSInputs() {
OP *hlslOP = HLM.GetOP();

Expand Down Expand Up @@ -1721,6 +1765,12 @@ void HLSignatureLower::GenerateGetMeshPayloadOperation() {
}
// Lower signatures.
void HLSignatureLower::Run() {

// Generate error and exit if semantic type
// is not one of the allowed types
if (!ValidateSemanticType(Entry))
return;

DxilFunctionProps &props = HLM.GetDxilFunctionProps(Entry);
if (props.IsGraphics()) {
if (props.IsMS()) {
Expand Down
3 changes: 3 additions & 0 deletions lib/HLSL/HLSignatureLower.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <unordered_set>
#include <unordered_map>
#include "dxc/DXIL/DxilConstants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Argument.h"

namespace llvm {
class Value;
Expand Down Expand Up @@ -53,6 +55,7 @@ class HLSignatureLower {
void GenerateDxilPrimOutputs();
void GenerateDxilInputsOutputs(DXIL::SignatureKind SK);
void GenerateDxilCSInputs();
bool ValidateSemanticType(llvm::Function* F);
void GenerateDxilPatchConstantLdSt();
void GenerateDxilPatchConstantFunctionInputs();
void GenerateClipPlanesForVS(llvm::Value *outPosition);
Expand Down
Loading

0 comments on commit cc65df2

Please sign in to comment.