From: Dejan Mircevski Date: Fri, 29 Apr 2016 17:40:01 +0000 (-0400) Subject: Add v1.1 capabilities validation. X-Git-Tag: upstream/2018.6~1250 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3732d6cc2146e8e1f1201aa6688c9efc997d42cf;p=platform%2Fupstream%2FSPIRV-Tools.git Add v1.1 capabilities validation. Refactor the ValidateCapability test fixture. Explain the meaning of test parameters. Factor out methods for convenience and readability. DRY v1.0 and v1.1 tests. --- diff --git a/test/Validate.Capability.cpp b/test/Validate.Capability.cpp index d9dc3d8..5d4e96b 100644 --- a/test/Validate.Capability.cpp +++ b/test/Validate.Capability.cpp @@ -40,18 +40,79 @@ namespace { using spvtest::ScopedContext; +using std::get; using std::make_pair; +using std::ostringstream; using std::pair; using std::string; -using std::stringstream; using std::tuple; using std::vector; using testing::Combine; using testing::Values; using testing::ValuesIn; -using ValidateCapability = - spvtest::ValidateBase>>>; +// Parameter for validation test fixtures. The first string is a capability +// name that will begin the assembly under test, the second the remainder +// assembly, and the vector at the end determines whether the test expects +// success or failure. See below for details and convenience methods to access +// each one. +// +// The assembly to test is composed from a variable top line and a fixed +// remainder. The top line will be an OpCapability instruction, while the +// remainder will be some assembly text that succeeds or fails to assemble +// depending on which capability was chosen. For instance, the following will +// succeed: +// +// OpCapability Pipes ; implies Kernel +// OpLifetimeStop %1 0 ; requires Kernel +// +// and the following will fail: +// +// OpCapability Kernel +// %1 = OpTypeNamedBarrier ; requires NamedBarrier +// +// So how does the test parameter capture which capabilities should cause +// success and which shouldn't? The answer is in the last element: it's a +// vector of capabilities that make the remainder assembly succeed. So if the +// first-line capability exists in that vector, success is expected; otherwise, +// failure is expected in the tests. +// +// We will use testing::Combine() to vary the first line: when we combine +// AllCapabilities() with a single remainder assembly, we generate enough test +// cases to try the assembly with every possible capability that could be +// declared. However, Combine() only produces tuples -- it cannot produce, say, +// a struct. Therefore, this type must be a tuple. +using CapTestParameter = tuple>>; + +const string& Capability(const CapTestParameter& p) { return get<0>(p); } +const string& Remainder(const CapTestParameter& p) { return get<1>(p).first; } +const vector& MustSucceed(const CapTestParameter& p) { + return get<1>(p).second; +} + +// Creates assembly to test from p. +string MakeAssembly(const CapTestParameter& p) { + ostringstream ss; + const string& capability = Capability(p); + if (!capability.empty()) { + ss << "OpCapability " << capability << "\n"; + } + ss << Remainder(p); + return ss.str(); +} + +// Expected validation result for p. +spv_result_t ExpectedResult(const CapTestParameter& p) { + const auto& caps = MustSucceed(p); + auto found = find(begin(caps), end(caps), Capability(p)); + return (found == end(caps)) ? SPV_ERROR_INVALID_CAPABILITY : SPV_SUCCESS; +} + +// Assembles using v1.0, unless the parameter's capability requires v1.1. +using ValidateCapability = spvtest::ValidateBase; + +// Always assembles using v1.1. +using ValidateCapabilityV11 = spvtest::ValidateBase; TEST_F(ValidateCapability, Default) { const char str[] = R"( @@ -127,7 +188,9 @@ const vector& AllCapabilities() { "StorageImageReadWithoutFormat", "StorageImageWriteWithoutFormat", "MultiViewport", - "SubgroupDispatch"}; + "SubgroupDispatch", + "NamedBarrier", + "PipeStorage"}; return *r; } @@ -255,7 +318,9 @@ const vector& KernelDependencies() { "DeviceEnqueue", "LiteralSampler", "Int8", - "SubgroupDispatch"}; + "SubgroupDispatch", + "NamedBarrier", + "PipeStorage"}; return *r; } @@ -489,8 +554,25 @@ make_pair(string(kGLSL450MemoryModel) + make_pair(string(kGLSL450MemoryModel) + "OpEntryPoint Kernel %func \"shader\" " "OpExecutionMode %func ContractionOff" + - string(kVoidFVoid), KernelDependencies()) -)),); + string(kVoidFVoid), KernelDependencies()))),); + +// clang-format on + +INSTANTIATE_TEST_CASE_P( + ExecutionModeV11, ValidateCapabilityV11, + Combine(ValuesIn(AllCapabilities()), + Values(make_pair(string(kOpenCLMemoryModel) + + "OpEntryPoint Kernel %func \"shader\" " + "OpExecutionMode %func SubgroupSize 1" + + string(kVoidFVoid), + vector{"SubgroupDispatch"}), + make_pair( + string(kOpenCLMemoryModel) + + "OpEntryPoint Kernel %func \"shader\" " + "OpExecutionMode %func SubgroupsPerWorkgroup 65535" + + string(kVoidFVoid), + vector{"SubgroupDispatch"}))), ); +// clang-format off INSTANTIATE_TEST_CASE_P(StorageClass, ValidateCapability, Combine( @@ -912,7 +994,7 @@ make_pair(string(kOpenCLMemoryModel) + // that can be used for operands where IDs are required. The assembly is valid, // apart from not declaring any capabilities required by the operands. string ImageOperandsTemplate(const string& operands) { - stringstream ss; + ostringstream ss; // clang-format off ss << R"( OpCapability Kernel @@ -965,33 +1047,22 @@ bool Exists(const std::string& capability, spv_target_env env) { } TEST_P(ValidateCapability, Capability) { - string capability; - pair> operation; - std::tie(capability, operation) = GetParam(); - stringstream ss; - if (!capability.empty()) { - ss << "OpCapability " + capability + " "; - } - - ss << operation.first; - - spv_result_t res = SPV_ERROR_INTERNAL; - auto& valid_capabilities = operation.second; - - auto it = - find(begin(valid_capabilities), end(valid_capabilities), capability); - if (it != end(valid_capabilities)) { - res = SPV_SUCCESS; - } else { - res = SPV_ERROR_INVALID_CAPABILITY; - } - + const string capability = Capability(GetParam()); spv_target_env env = (capability.empty() || Exists(capability, SPV_ENV_UNIVERSAL_1_0)) ? SPV_ENV_UNIVERSAL_1_0 : SPV_ENV_UNIVERSAL_1_1; - CompileSuccessfully(ss.str(), env); - ASSERT_EQ(res, ValidateInstructions(env)) << ss.str(); + const string test_code = MakeAssembly(GetParam()); + CompileSuccessfully(test_code, env); + ASSERT_EQ(ExpectedResult(GetParam()), ValidateInstructions(env)) << test_code; +} + +TEST_P(ValidateCapabilityV11, Capability) { + const string test_code = MakeAssembly(GetParam()); + CompileSuccessfully(test_code, SPV_ENV_UNIVERSAL_1_1); + ASSERT_EQ(ExpectedResult(GetParam()), + ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)) + << test_code; } } // namespace anonymous