sema: check input patch size mismatch earlier. (#6363)

The check was done in the DXIL backend, and not in the SPIR-V backend.
This causes the issue to be ignored on the SPIR-V side. Moved the check
earlier to SEMA so a single check works for both backends.

I had to split the existing HLSL check as it doesn't support having 2
run lines (AFAIK).

Fixes #3739

---------

Signed-off-by: Nathan Gauër <brioche@google.com>
This commit is contained in:
Nathan Gauër 2024-03-07 11:26:56 +01:00 коммит произвёл GitHub
Родитель ec5b8aaba3
Коммит cbbf459969
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
6 изменённых файлов: 124 добавлений и 19 удалений

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

@ -7834,6 +7834,8 @@ def err_hlsl_missing_patch_constant_function : Error<
"patch constant function '%0' must be defined">;
def err_hlsl_patch_reachability_not_allowed : Error<
"%select{patch constant|entry}0 function '%1' should not be reachable from %select{patch constant|entry}2 function '%3'">;
def err_hlsl_patch_input_size_mismatch : Error<
"Patch constant function's input patch input should have %0 elements, but has %1.">;
def warn_hlsl_structurize_exits_lifetime_markers_conflict : Warning <
"structurize-returns skipped function '%0' due to incompatibility with lifetime markers. Use -disable-lifetime-markers to enable structurize-exits on this function.">,
InGroup< HLSLStructurizeExitsLifetimeMarkersConflict >;

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

@ -1496,18 +1496,6 @@ void SetPatchConstantFunctionWithAttr(
if (patchConstantFunctionPropsMap.count(patchConstFunc)) {
const DxilFunctionProps &patchProps =
*patchConstantFunctionPropsMap[patchConstFunc];
if (patchProps.ShaderProps.HS.inputControlPoints != 0 &&
patchProps.ShaderProps.HS.inputControlPoints !=
HSProps->ShaderProps.HS.inputControlPoints) {
clang::DiagnosticsEngine &Diags = CGM.getDiags();
unsigned DiagID =
Diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
"Patch constant function's input patch input "
"should have %0 elements, but has %1.");
Diags.Report(Entry->second.SL, DiagID)
<< HSProps->ShaderProps.HS.inputControlPoints
<< patchProps.ShaderProps.HS.inputControlPoints;
}
if (patchProps.ShaderProps.HS.outputControlPoints != 0 &&
patchProps.ShaderProps.HS.outputControlPoints !=
HSProps->ShaderProps.HS.outputControlPoints) {

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

@ -19,6 +19,7 @@
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Sema/SemaHLSL.h"
#include "llvm/Support/Debug.h"
#include <optional>
using namespace clang;
using namespace llvm;
@ -332,6 +333,17 @@ private:
std::set<CXXMemberCallExpr *> &DiagnosedCalls;
};
std::optional<uint32_t>
getFunctionInputPatchCount(const FunctionDecl *function) {
for (const auto *param : function->params()) {
if (!hlsl::IsHLSLInputPatchType(param->getType()))
continue;
return hlsl::GetHLSLInputPatchCount(param->getType());
}
return std::nullopt;
}
} // namespace
void hlsl::DiagnoseTranslationUnit(clang::Sema *self) {
@ -462,6 +474,15 @@ void hlsl::DiagnoseTranslationUnit(clang::Sema *self) {
<< 0 << pPatchFnDecl->getName() << 1 << FDecl->getName();
}
}
auto hullPatchCount = getFunctionInputPatchCount(pPatchFnDecl);
auto functionPatchCount = getFunctionInputPatchCount(FDecl);
if (hullPatchCount.has_value() && functionPatchCount.has_value() &&
hullPatchCount.value() != functionPatchCount.value()) {
self->Diag(pPatchFnDecl->getSourceRange().getBegin(),
diag::err_hlsl_patch_input_size_mismatch)
<< functionPatchCount.value() << hullPatchCount.value();
}
}
DXIL::ShaderKind EntrySK = shaderModel->GetKind();

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

@ -0,0 +1,22 @@
// RUN: %dxc -T hs_6_0 -E main %s -spirv -verify
struct ControlPoint { float4 position : POSITION; };
struct HullPatchOut {
float edge [3] : SV_TessFactor;
float inside : SV_InsideTessFactor;
};
HullPatchOut HullConst (InputPatch<ControlPoint,2> v) { /* expected-error{{Patch constant function's input patch input should have 3 elements, but has 2.}} */
return (HullPatchOut)0;
}
[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[patchconstantfunc("HullConst")]
[outputcontrolpoints(0)]
ControlPoint main(InputPatch<ControlPoint,3> v, uint id : SV_OutputControlPointID) {
return v[id];
}

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

@ -0,0 +1,76 @@
// RUN: %dxc -E main -T hs_6_0 %s | FileCheck %s
// CHECK-DAG: Patch Constant function HSPerPatchFunc should not have inout param
// CHECK-DAG: Patch constant function's output patch input should have 3 elements, but has 5.
//--------------------------------------------------------------------------------------
// SimpleTessellation.hlsl
//
// Advanced Technology Group (ATG)
// Copyright (C) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
struct PSSceneIn
{
float4 pos : SV_Position;
float2 tex : TEXCOORD0;
float3 norm : NORMAL;
uint RTIndex : SV_RenderTargetArrayIndex;
};
//////////////////////////////////////////////////////////////////////////////////////////
// Simple forwarding Tessellation shaders
struct HSPerVertexData
{
// This is just the original vertex verbatim. In many real life cases this would be a
// control point instead
PSSceneIn v;
};
struct HSPerPatchData
{
// We at least have to specify tess factors per patch
// As we're tesselating triangles, there will be 4 tess factors
// In real life case this might contain face normal, for example
float edges[ 3 ] : SV_TessFactor;
float inside : SV_InsideTessFactor;
};
float4 HSPerPatchFunc()
{
return 1.8;
}
HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 12 > points, OutputPatch<HSPerVertexData, 5> outp, inout float x)
{
HSPerPatchData d;
d.edges[ 0 ] = 1;
d.edges[ 1 ] = 1;
d.edges[ 2 ] = 1;
d.inside = 1;
return d;
}
// hull per-control point shader
[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[patchconstantfunc("HSPerPatchFunc")]
[outputcontrolpoints(3)]
HSPerVertexData main(const uint id : SV_OutputControlPointID,
const InputPatch< PSSceneIn, 12 > points )
{
HSPerVertexData v;
// Just forward the vertex
v.v = points[ id ];
return v;
}

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

@ -1,8 +1,6 @@
// RUN: %dxc -E main -T hs_6_0 %s | FileCheck %s
// CHECK-DAG: Patch Constant function HSPerPatchFunc should not have inout param
// CHECK-DAG: Patch constant function's input patch input should have 3 elements, but has 12.
// CHECK-DAG: Patch constant function's output patch input should have 3 elements, but has 5.
//--------------------------------------------------------------------------------------
// SimpleTessellation.hlsl
@ -46,7 +44,7 @@ float4 HSPerPatchFunc()
return 1.8;
}
HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 12 > points, OutputPatch<HSPerVertexData, 5> outp, inout float x)
HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 12 > points, OutputPatch<HSPerVertexData, 3> outp)
{
HSPerPatchData d;
@ -64,8 +62,8 @@ HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 12 > points, OutputP
[outputtopology("triangle_cw")]
[patchconstantfunc("HSPerPatchFunc")]
[outputcontrolpoints(3)]
HSPerVertexData main( const uint id : SV_OutputControlPointID,
const InputPatch< PSSceneIn, 3 > points )
HSPerVertexData main(const uint id : SV_OutputControlPointID,
const InputPatch< PSSceneIn, 3 > points )
{
HSPerVertexData v;
@ -74,5 +72,3 @@ HSPerVertexData main( const uint id : SV_OutputControlPointID,
return v;
}