Browse Source

Add validation for Quad operations against non pixel shaders (#986)

Young Kim 7 years ago
parent
commit
a43147de94

+ 11 - 1
lib/HLSL/DxilValidation.cpp

@@ -234,7 +234,7 @@ const char *hlsl::GetValidationRuleText(ValidationRule value) {
     case hlsl::ValidationRule::SmResourceRangeOverlap: return "Resource %0 with base %1 size %2 overlap with other resource with base %3 size %4 in space %5";
     case hlsl::ValidationRule::SmCBufferOffsetOverlap: return "CBuffer %0 has offset overlaps at %1";
     case hlsl::ValidationRule::SmCBufferElementOverflow: return "CBuffer %0 size insufficient for element at offset %1";
-    case hlsl::ValidationRule::SmOpcodeInInvalidFunction: return "opcode '%0' should only used in '%1'";
+    case hlsl::ValidationRule::SmOpcodeInInvalidFunction: return "opcode '%0' should only be used in '%1'";
     case hlsl::ValidationRule::SmViewIDNeedsSlot: return "Pixel shader input signature lacks available space for ViewID";
     case hlsl::ValidationRule::UniNoWaveSensitiveGradient: return "Gradient operations are not affected by wave-sensitive data or control flow.";
     case hlsl::ValidationRule::FlowReducible: return "Execution flow must be reducible";
@@ -1920,6 +1920,16 @@ static void ValidateDxilOperationCallInProfile(CallInst *CI,
   case DXIL::OpCode::ViewID:
     ValCtx.hasViewID = true;
     break;
+  case DXIL::OpCode::QuadOp:
+    if (!pSM->IsPS())
+      ValCtx.EmitFormatError(ValidationRule::SmOpcodeInInvalidFunction,
+                             {"QuadReadAcross", "Pixel Shader"});
+    break;
+  case DXIL::OpCode::QuadReadLaneAt:
+    if (!pSM->IsPS())
+      ValCtx.EmitFormatError(ValidationRule::SmOpcodeInInvalidFunction,
+                             {"QuadReadLaneAt", "Pixel Shader"});
+    break;
   default:
     // Skip opcodes don't need special check.
     break;

+ 1 - 0
tools/clang/unittests/HLSL/LinkerTest.cpp

@@ -281,6 +281,7 @@ TEST_F(LinkerTest, RunLinkNoAlloca) {
 }
 
 TEST_F(LinkerTest, RunLinkFailSelectRes) {
+  if (m_ver.SkipDxilVersion(1, 3)) return;
   CComPtr<IDxcBlob> pEntryLib;
   CompileLib(L"..\\CodeGenHLSL\\lib_select_res_entry.hlsl", &pEntryLib);
   CComPtr<IDxcBlob> pLib;

+ 22 - 3
tools/clang/unittests/HLSL/ValidationTest.cpp

@@ -268,6 +268,7 @@ public:
   TEST_METHOD(InvalidSigCompTyFail);
   TEST_METHOD(MultiStream2Fail);
   TEST_METHOD(PhiTGSMFail);
+  TEST_METHOD(QuadOpInCS);
   TEST_METHOD(ReducibleFail);
   TEST_METHOD(SampleBiasFail);
   TEST_METHOD(SamplerKindFail);
@@ -867,6 +868,21 @@ TEST_F(ValidationTest, PhiTGSMFail) {
       "ret void",
       "TGSM pointers must originate from an unambiguous TGSM global variable");
 }
+
+TEST_F(ValidationTest, QuadOpInCS) {
+  if (m_ver.SkipDxilVersion(1, 3)) return;
+  RewriteAssemblyCheckMsg(
+      "struct PerThreadData { int "
+      "input; int output; }; RWStructuredBuffer<PerThreadData> g_sb; "
+      "[numthreads(8, 12, 1)] void main(uint GI : SV_GroupIndex) "
+      "{ PerThreadData pts = g_sb[GI]; pts.output = "
+      "WaveActiveSum(pts.input); g_sb[GI] = pts; }; ",
+      "cs_6_0", {"@dx.op.waveActiveOp.i32(i32 119", "declare i32 @dx.op.waveActiveOp.i32(i32, i32, i8, i8)"},
+      {"@dx.op.quadOp.i32(i32 123", "declare i32 @dx.op.quadOp.i32(i32, i32, i8, i8)"},
+      "'QuadReadAcross' should only be used in 'Pixel Shader'"
+      );
+}
+
 TEST_F(ValidationTest, ReducibleFail) {
   if (m_ver.SkipIRSensitiveTest()) return;
   RewriteAssemblyCheckMsg(
@@ -1627,6 +1643,7 @@ TEST_F(ValidationTest, WhenMetaFlagsUsageThenFail) {
 }
 
 TEST_F(ValidationTest, StorePatchControlNotInPatchConstantFunction) {
+  if (m_ver.SkipDxilVersion(1, 3)) return;
   RewriteAssemblyCheckMsg(
       "struct PSSceneIn \
     { \
@@ -1674,10 +1691,11 @@ HSPerVertexData main( const uint id : SV_OutputControlPointID,\
       "hs_6_0", 
       "dx.op.storeOutput.f32(i32 5",
       "dx.op.storePatchConstant.f32(i32 106",
-      "opcode 'StorePatchConstant' should only used in 'PatchConstant function'");
+      "opcode 'StorePatchConstant' should only be used in 'PatchConstant function'");
 }
 
 TEST_F(ValidationTest, LoadOutputControlPointNotInPatchConstantFunction) {
+  if (m_ver.SkipDxilVersion(1, 3)) return;
   RewriteAssemblyCheckMsg(
       "struct PSSceneIn \
     { \
@@ -1725,10 +1743,11 @@ HSPerVertexData main( const uint id : SV_OutputControlPointID,\
       "hs_6_0",
       "dx.op.loadInput.f32(i32 4",
       "dx.op.loadOutputControlPoint.f32(i32 103",
-      "opcode 'LoadOutputControlPoint' should only used in 'PatchConstant function'");
+      "opcode 'LoadOutputControlPoint' should only be used in 'PatchConstant function'");
 }
 
 TEST_F(ValidationTest, OutputControlPointIDInPatchConstantFunction) {
+  if (m_ver.SkipDxilVersion(1, 3)) return;
   RewriteAssemblyCheckMsg(
       "struct PSSceneIn \
     { \
@@ -1776,7 +1795,7 @@ HSPerVertexData main( const uint id : SV_OutputControlPointID,\
       "hs_6_0",
       "ret void",
       "call i32 @dx.op.outputControlPointID.i32(i32 107)\n ret void",
-      "opcode 'OutputControlPointID' should only used in 'hull function'");
+      "opcode 'OutputControlPointID' should only be used in 'hull function'");
 }
 
 TEST_F(ValidationTest, ClipCullMaxComponents) {

+ 1 - 1
utils/hct/hctdb.py

@@ -1779,7 +1779,7 @@ class db_dxil(object):
         self.add_valrule_msg("Sm.ResourceRangeOverlap", "Resource ranges must not overlap", "Resource %0 with base %1 size %2 overlap with other resource with base %3 size %4 in space %5")
         self.add_valrule_msg("Sm.CBufferOffsetOverlap", "CBuffer offsets must not overlap", "CBuffer %0 has offset overlaps at %1")
         self.add_valrule_msg("Sm.CBufferElementOverflow", "CBuffer elements must not overflow", "CBuffer %0 size insufficient for element at offset %1")
-        self.add_valrule_msg("Sm.OpcodeInInvalidFunction", "Invalid DXIL opcode usage like StorePatchConstant in patch constant function", "opcode '%0' should only used in '%1'")
+        self.add_valrule_msg("Sm.OpcodeInInvalidFunction", "Invalid DXIL opcode usage like StorePatchConstant in patch constant function", "opcode '%0' should only be used in '%1'")
         self.add_valrule_msg("Sm.ViewIDNeedsSlot", "ViewID requires compatible space in pixel shader input signature", "Pixel shader input signature lacks available space for ViewID")
 
         # fxc relaxed check of gradient check.