2016-01-07 18:44:22 +00:00
|
|
|
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
2015-05-22 17:26:19 +00:00
|
|
|
//
|
2016-09-01 19:33:59 +00:00
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
2015-05-22 17:26:19 +00:00
|
|
|
//
|
2016-09-01 19:33:59 +00:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2015-05-22 17:26:19 +00:00
|
|
|
//
|
2016-09-01 19:33:59 +00:00
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2015-05-22 17:26:19 +00:00
|
|
|
|
2015-10-30 20:06:15 +00:00
|
|
|
#include <sstream>
|
2018-08-03 19:06:09 +00:00
|
|
|
#include <string>
|
|
|
|
#include <tuple>
|
|
|
|
#include <vector>
|
2015-10-30 20:06:15 +00:00
|
|
|
|
|
|
|
#include "gmock/gmock.h"
|
2016-03-31 16:16:51 +00:00
|
|
|
#include "source/spirv_constant.h"
|
2018-08-03 19:06:09 +00:00
|
|
|
#include "test/test_fixture.h"
|
|
|
|
#include "test/unit_spirv.h"
|
2015-11-11 19:24:04 +00:00
|
|
|
|
2018-07-11 13:24:49 +00:00
|
|
|
namespace spvtools {
|
2016-04-21 19:46:08 +00:00
|
|
|
namespace {
|
|
|
|
|
2015-10-01 20:58:17 +00:00
|
|
|
using spvtest::AutoText;
|
2016-04-21 19:46:08 +00:00
|
|
|
using spvtest::ScopedContext;
|
2015-11-12 15:45:36 +00:00
|
|
|
using spvtest::TextToBinaryTest;
|
2017-11-27 15:16:41 +00:00
|
|
|
using ::testing::Combine;
|
|
|
|
using ::testing::Eq;
|
|
|
|
using ::testing::HasSubstr;
|
2015-09-25 16:43:37 +00:00
|
|
|
|
2015-05-22 17:26:19 +00:00
|
|
|
class BinaryToText : public ::testing::Test {
|
|
|
|
public:
|
2019-01-16 21:53:10 +00:00
|
|
|
BinaryToText()
|
|
|
|
: context(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)), binary(nullptr) {}
|
|
|
|
~BinaryToText() {
|
|
|
|
spvBinaryDestroy(binary);
|
|
|
|
spvContextDestroy(context);
|
|
|
|
}
|
2015-11-12 18:48:30 +00:00
|
|
|
|
2015-05-22 17:26:19 +00:00
|
|
|
virtual void SetUp() {
|
2015-08-24 19:52:26 +00:00
|
|
|
const char* textStr = R"(
|
2015-11-11 17:32:21 +00:00
|
|
|
OpSource OpenCL_C 12
|
2015-08-21 15:52:29 +00:00
|
|
|
OpMemoryModel Physical64 OpenCL
|
|
|
|
OpSourceExtension "PlaceholderExtensionName"
|
Use opcode operand definitions from SPIR-V specification generator.
The assembler and disassembler now use a dynamically adjusted
sequence of expected operand types. (Internally, it is a deque,
for readability.) Both parsers repeatedly pull an expected operand
type from the left of this pattern list, and try to match the next
input token against it.
The expected pattern is adjusted during the parse to accommodate:
- an extended instruction's expected operands, depending on the
extended instruction's index.
- when an operand itself has operands
- to handle sequences of zero or more operands, or pairs of
operands. These are expanded lazily during the parse.
Adds spv::OperandClass from the SPIR-V specification generator.
Modifies spv_operand_desc_t:
- adds hasResult, hasType, and operandClass array to the opcode
description type.
- "wordCount" is replaced with "numTypes", which counts the number
of entries in operandTypes. And each of those describes a
*logical* operand, including the type id for the instruction,
and the result id for the instruction. A logical operand could be
variable-width, such as a literal string.
Adds opcode.inc, an automatically-generated table of operation
descriptions, with one line to describe each core instruction.
Externally, we have modified the SPIR-V spec doc generator to
emit this file.
(We have hacked this copy to use the old semantics for OpLine.)
Inside the assembler, parsing an operand may fail with new
error code SPV_FAIL_MATCH. For an optional operand, this is not
fatal, but should trigger backtracking at a higher level.
The spvTextIsStartOfNewInst checks the case of the third letter
of what might be an opcode. So now, "OpenCL" does not look like
an opcode name.
In assembly, the EntryPoint name field is mandatory, but can be
an empty string.
Adjust tests for changes to:
- OpSampedImage
- OpTypeSampler
2015-08-27 17:03:52 +00:00
|
|
|
OpEntryPoint Kernel %1 "foo"
|
2015-08-21 15:52:29 +00:00
|
|
|
OpExecutionMode %1 LocalSizeHint 1 1 1
|
|
|
|
%2 = OpTypeVoid
|
|
|
|
%3 = OpTypeBool
|
|
|
|
%4 = OpTypeInt 8 0
|
|
|
|
%5 = OpTypeInt 8 1
|
|
|
|
%6 = OpTypeInt 16 0
|
|
|
|
%7 = OpTypeInt 16 1
|
|
|
|
%8 = OpTypeInt 32 0
|
|
|
|
%9 = OpTypeInt 32 1
|
|
|
|
%10 = OpTypeInt 64 0
|
|
|
|
%11 = OpTypeInt 64 1
|
|
|
|
%12 = OpTypeFloat 16
|
|
|
|
%13 = OpTypeFloat 32
|
|
|
|
%14 = OpTypeFloat 64
|
2015-09-22 19:50:33 +00:00
|
|
|
%15 = OpTypeVector %4 2
|
2015-05-22 17:26:19 +00:00
|
|
|
)";
|
|
|
|
spv_text_t text = {textStr, strlen(textStr)};
|
|
|
|
spv_diagnostic diagnostic = nullptr;
|
2015-09-09 17:04:32 +00:00
|
|
|
spv_result_t error =
|
2015-11-12 18:48:30 +00:00
|
|
|
spvTextToBinary(context, text.str, text.length, &binary, &diagnostic);
|
2019-01-16 21:53:10 +00:00
|
|
|
spvDiagnosticPrint(diagnostic);
|
|
|
|
spvDiagnosticDestroy(diagnostic);
|
|
|
|
ASSERT_EQ(SPV_SUCCESS, error);
|
2015-05-22 17:26:19 +00:00
|
|
|
}
|
|
|
|
|
2019-01-16 21:53:10 +00:00
|
|
|
virtual void TearDown() {
|
|
|
|
spvBinaryDestroy(binary);
|
|
|
|
binary = nullptr;
|
|
|
|
}
|
2015-05-22 17:26:19 +00:00
|
|
|
|
2015-10-30 20:06:15 +00:00
|
|
|
// Compiles the given assembly text, and saves it into 'binary'.
|
|
|
|
void CompileSuccessfully(std::string text) {
|
2019-01-16 21:53:10 +00:00
|
|
|
spvBinaryDestroy(binary);
|
|
|
|
binary = nullptr;
|
2015-10-30 20:06:15 +00:00
|
|
|
spv_diagnostic diagnostic = nullptr;
|
2015-11-12 18:48:30 +00:00
|
|
|
EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.c_str(), text.size(),
|
|
|
|
&binary, &diagnostic));
|
2015-10-30 20:06:15 +00:00
|
|
|
}
|
|
|
|
|
2015-11-12 18:48:30 +00:00
|
|
|
spv_context context;
|
2015-05-22 17:26:19 +00:00
|
|
|
spv_binary binary;
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_F(BinaryToText, Default) {
|
|
|
|
spv_text text = nullptr;
|
|
|
|
spv_diagnostic diagnostic = nullptr;
|
2015-11-12 18:48:30 +00:00
|
|
|
ASSERT_EQ(
|
|
|
|
SPV_SUCCESS,
|
|
|
|
spvBinaryToText(context, binary->code, binary->wordCount,
|
|
|
|
SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic));
|
2015-05-22 17:26:19 +00:00
|
|
|
printf("%s", text->str);
|
|
|
|
spvTextDestroy(text);
|
|
|
|
}
|
|
|
|
|
2015-10-30 20:06:15 +00:00
|
|
|
TEST_F(BinaryToText, MissingModule) {
|
2015-05-22 17:26:19 +00:00
|
|
|
spv_text text;
|
|
|
|
spv_diagnostic diagnostic = nullptr;
|
2015-11-12 18:48:30 +00:00
|
|
|
EXPECT_EQ(
|
|
|
|
SPV_ERROR_INVALID_BINARY,
|
|
|
|
spvBinaryToText(context, nullptr, 42, SPV_BINARY_TO_TEXT_OPTION_NONE,
|
|
|
|
&text, &diagnostic));
|
2015-10-30 20:06:15 +00:00
|
|
|
EXPECT_THAT(diagnostic->error, Eq(std::string("Missing module.")));
|
2015-05-22 17:26:19 +00:00
|
|
|
if (diagnostic) {
|
|
|
|
spvDiagnosticPrint(diagnostic);
|
|
|
|
spvDiagnosticDestroy(diagnostic);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-30 20:06:15 +00:00
|
|
|
TEST_F(BinaryToText, TruncatedModule) {
|
|
|
|
// Make a valid module with zero instructions.
|
|
|
|
CompileSuccessfully("");
|
|
|
|
EXPECT_EQ(SPV_INDEX_INSTRUCTION, binary->wordCount);
|
|
|
|
|
2015-11-18 14:22:10 +00:00
|
|
|
for (size_t length = 0; length < SPV_INDEX_INSTRUCTION; length++) {
|
2015-10-30 20:06:15 +00:00
|
|
|
spv_text text = nullptr;
|
|
|
|
spv_diagnostic diagnostic = nullptr;
|
2015-11-11 16:33:26 +00:00
|
|
|
EXPECT_EQ(
|
|
|
|
SPV_ERROR_INVALID_BINARY,
|
2015-11-12 18:48:30 +00:00
|
|
|
spvBinaryToText(context, binary->code, length,
|
|
|
|
SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic));
|
2015-10-30 20:06:15 +00:00
|
|
|
ASSERT_NE(nullptr, diagnostic);
|
|
|
|
std::stringstream expected;
|
|
|
|
expected << "Module has incomplete header: only " << length
|
|
|
|
<< " words instead of " << SPV_INDEX_INSTRUCTION;
|
|
|
|
EXPECT_THAT(diagnostic->error, Eq(expected.str()));
|
|
|
|
spvDiagnosticDestroy(diagnostic);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(BinaryToText, InvalidMagicNumber) {
|
|
|
|
CompileSuccessfully("");
|
|
|
|
std::vector<uint32_t> damaged_binary(binary->code,
|
|
|
|
binary->code + binary->wordCount);
|
|
|
|
damaged_binary[SPV_INDEX_MAGIC_NUMBER] ^= 123;
|
|
|
|
|
|
|
|
spv_diagnostic diagnostic = nullptr;
|
|
|
|
spv_text text;
|
2015-11-11 16:33:26 +00:00
|
|
|
EXPECT_EQ(
|
|
|
|
SPV_ERROR_INVALID_BINARY,
|
2015-11-12 18:48:30 +00:00
|
|
|
spvBinaryToText(context, damaged_binary.data(), damaged_binary.size(),
|
2015-11-11 16:33:26 +00:00
|
|
|
SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic));
|
2015-10-30 20:06:15 +00:00
|
|
|
ASSERT_NE(nullptr, diagnostic);
|
|
|
|
std::stringstream expected;
|
|
|
|
expected << "Invalid SPIR-V magic number '" << std::hex
|
|
|
|
<< damaged_binary[SPV_INDEX_MAGIC_NUMBER] << "'.";
|
|
|
|
EXPECT_THAT(diagnostic->error, Eq(expected.str()));
|
|
|
|
spvDiagnosticDestroy(diagnostic);
|
|
|
|
}
|
|
|
|
|
2015-10-16 19:11:00 +00:00
|
|
|
struct FailedDecodeCase {
|
|
|
|
std::string source_text;
|
|
|
|
std::vector<uint32_t> appended_instruction;
|
|
|
|
std::string expected_error_message;
|
|
|
|
};
|
|
|
|
|
|
|
|
using BinaryToTextFail =
|
2015-11-02 14:41:20 +00:00
|
|
|
spvtest::TextToBinaryTestBase<::testing::TestWithParam<FailedDecodeCase>>;
|
2015-10-16 19:11:00 +00:00
|
|
|
|
|
|
|
TEST_P(BinaryToTextFail, EncodeSuccessfullyDecodeFailed) {
|
|
|
|
EXPECT_THAT(EncodeSuccessfullyDecodeFailed(GetParam().source_text,
|
|
|
|
GetParam().appended_instruction),
|
|
|
|
Eq(GetParam().expected_error_message));
|
|
|
|
}
|
|
|
|
|
2019-01-29 23:56:52 +00:00
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
2015-10-30 20:06:15 +00:00
|
|
|
InvalidIds, BinaryToTextFail,
|
|
|
|
::testing::ValuesIn(std::vector<FailedDecodeCase>{
|
|
|
|
{"", spvtest::MakeInstruction(SpvOpTypeVoid, {0}),
|
|
|
|
"Error: Result Id is 0"},
|
|
|
|
{"", spvtest::MakeInstruction(SpvOpConstant, {0, 1, 42}),
|
|
|
|
"Error: Type Id is 0"},
|
|
|
|
{"%1 = OpTypeVoid", spvtest::MakeInstruction(SpvOpTypeVoid, {1}),
|
|
|
|
"Id 1 is defined more than once"},
|
|
|
|
{"%1 = OpTypeVoid\n"
|
|
|
|
"%2 = OpNot %1 %foo",
|
|
|
|
spvtest::MakeInstruction(SpvOpNot, {1, 2, 3}),
|
|
|
|
"Id 2 is defined more than once"},
|
|
|
|
{"%1 = OpTypeVoid\n"
|
|
|
|
"%2 = OpNot %1 %foo",
|
|
|
|
spvtest::MakeInstruction(SpvOpNot, {1, 1, 3}),
|
|
|
|
"Id 1 is defined more than once"},
|
|
|
|
// The following are the two failure cases for
|
|
|
|
// Parser::setNumericTypeInfoForType.
|
|
|
|
{"", spvtest::MakeInstruction(SpvOpConstant, {500, 1, 42}),
|
|
|
|
"Type Id 500 is not a type"},
|
|
|
|
{"%1 = OpTypeInt 32 0\n"
|
|
|
|
"%2 = OpTypeVector %1 4",
|
|
|
|
spvtest::MakeInstruction(SpvOpConstant, {2, 3, 999}),
|
|
|
|
"Type Id 2 is not a scalar numeric type"},
|
2019-01-29 23:56:52 +00:00
|
|
|
}));
|
2015-10-30 20:06:15 +00:00
|
|
|
|
2019-01-29 23:56:52 +00:00
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
2015-10-30 20:06:15 +00:00
|
|
|
InvalidIdsCheckedDuringLiteralCaseParsing, BinaryToTextFail,
|
|
|
|
::testing::ValuesIn(std::vector<FailedDecodeCase>{
|
|
|
|
{"", spvtest::MakeInstruction(SpvOpSwitch, {1, 2, 3, 4}),
|
|
|
|
"Invalid OpSwitch: selector id 1 has no type"},
|
|
|
|
{"%1 = OpTypeVoid\n",
|
|
|
|
spvtest::MakeInstruction(SpvOpSwitch, {1, 2, 3, 4}),
|
|
|
|
"Invalid OpSwitch: selector id 1 is a type, not a value"},
|
|
|
|
{"%1 = OpConstantTrue !500",
|
|
|
|
spvtest::MakeInstruction(SpvOpSwitch, {1, 2, 3, 4}),
|
|
|
|
"Type Id 500 is not a type"},
|
|
|
|
{"%1 = OpTypeFloat 32\n%2 = OpConstant %1 1.5",
|
|
|
|
spvtest::MakeInstruction(SpvOpSwitch, {2, 3, 4, 5}),
|
|
|
|
"Invalid OpSwitch: selector id 2 is not a scalar integer"},
|
2019-01-29 23:56:52 +00:00
|
|
|
}));
|
2015-10-16 19:11:00 +00:00
|
|
|
|
2015-11-12 15:45:36 +00:00
|
|
|
TEST_F(TextToBinaryTest, OneInstruction) {
|
|
|
|
const std::string input = "OpSource OpenCL_C 12\n";
|
|
|
|
EXPECT_EQ(input, EncodeAndDecodeSuccessfully(input));
|
2015-08-31 17:34:28 +00:00
|
|
|
}
|
|
|
|
|
2015-08-31 18:07:22 +00:00
|
|
|
// Exercise the case where an operand itself has operands.
|
|
|
|
// This could detect problems in updating the expected-set-of-operands
|
|
|
|
// list.
|
2015-11-12 15:45:36 +00:00
|
|
|
TEST_F(TextToBinaryTest, OperandWithOperands) {
|
|
|
|
const std::string input = R"(OpEntryPoint Kernel %1 "foo"
|
|
|
|
OpExecutionMode %1 LocalSizeHint 100 200 300
|
|
|
|
%2 = OpTypeVoid
|
|
|
|
%3 = OpTypeFunction %2
|
|
|
|
%1 = OpFunction %1 None %3
|
2015-09-14 19:22:23 +00:00
|
|
|
)";
|
2015-11-12 15:45:36 +00:00
|
|
|
EXPECT_EQ(input, EncodeAndDecodeSuccessfully(input));
|
2015-09-14 19:22:23 +00:00
|
|
|
}
|
|
|
|
|
2016-07-05 14:21:21 +00:00
|
|
|
using RoundTripInstructionsTest = spvtest::TextToBinaryTestBase<
|
2018-08-01 18:58:12 +00:00
|
|
|
::testing::TestWithParam<std::tuple<spv_target_env, std::string>>>;
|
2015-09-25 16:43:37 +00:00
|
|
|
|
|
|
|
TEST_P(RoundTripInstructionsTest, Sample) {
|
2018-08-01 18:58:12 +00:00
|
|
|
EXPECT_THAT(EncodeAndDecodeSuccessfully(std::get<1>(GetParam()),
|
2016-07-05 14:21:21 +00:00
|
|
|
SPV_BINARY_TO_TEXT_OPTION_NONE,
|
2018-08-01 18:58:12 +00:00
|
|
|
std::get<0>(GetParam())),
|
|
|
|
Eq(std::get<1>(GetParam())));
|
2016-03-18 18:13:16 +00:00
|
|
|
}
|
2015-09-25 16:43:37 +00:00
|
|
|
|
2017-03-14 16:43:41 +00:00
|
|
|
// clang-format off
|
2019-01-29 23:56:52 +00:00
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
2016-10-13 19:17:11 +00:00
|
|
|
NumericLiterals, RoundTripInstructionsTest,
|
|
|
|
// This test is independent of environment, so just test the one.
|
2017-03-14 16:43:41 +00:00
|
|
|
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
2018-02-09 19:29:02 +00:00
|
|
|
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
2016-10-13 19:17:11 +00:00
|
|
|
::testing::ValuesIn(std::vector<std::string>{
|
|
|
|
"%1 = OpTypeInt 12 0\n%2 = OpConstant %1 1867\n",
|
|
|
|
"%1 = OpTypeInt 12 1\n%2 = OpConstant %1 1867\n",
|
|
|
|
"%1 = OpTypeInt 12 1\n%2 = OpConstant %1 -1867\n",
|
|
|
|
"%1 = OpTypeInt 32 0\n%2 = OpConstant %1 1867\n",
|
|
|
|
"%1 = OpTypeInt 32 1\n%2 = OpConstant %1 1867\n",
|
|
|
|
"%1 = OpTypeInt 32 1\n%2 = OpConstant %1 -1867\n",
|
|
|
|
"%1 = OpTypeInt 64 0\n%2 = OpConstant %1 18446744073709551615\n",
|
|
|
|
"%1 = OpTypeInt 64 1\n%2 = OpConstant %1 9223372036854775807\n",
|
|
|
|
"%1 = OpTypeInt 64 1\n%2 = OpConstant %1 -9223372036854775808\n",
|
|
|
|
// 16-bit floats print as hex floats.
|
|
|
|
"%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ff4p+16\n",
|
|
|
|
"%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.d2cp-10\n",
|
|
|
|
// 32-bit floats
|
2018-03-30 23:35:45 +00:00
|
|
|
"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -3.125\n",
|
2016-10-13 19:17:11 +00:00
|
|
|
"%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.8p+128\n", // NaN
|
|
|
|
"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0002p+128\n", // NaN
|
|
|
|
"%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1p+128\n", // Inf
|
|
|
|
"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1p+128\n", // -Inf
|
|
|
|
// 64-bit floats
|
2018-03-30 23:35:45 +00:00
|
|
|
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -3.125\n",
|
2016-10-13 19:17:11 +00:00
|
|
|
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.ffffffffffffap-1023\n", // small normal
|
|
|
|
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.ffffffffffffap-1023\n",
|
|
|
|
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.8p+1024\n", // NaN
|
|
|
|
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0002p+1024\n", // NaN
|
|
|
|
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1p+1024\n", // Inf
|
|
|
|
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1p+1024\n", // -Inf
|
2019-01-29 23:56:52 +00:00
|
|
|
})));
|
2017-03-14 16:43:41 +00:00
|
|
|
// clang-format on
|
2016-10-13 19:17:11 +00:00
|
|
|
|
2019-01-29 23:56:52 +00:00
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
2015-09-25 16:43:37 +00:00
|
|
|
MemoryAccessMasks, RoundTripInstructionsTest,
|
2017-03-14 16:43:41 +00:00
|
|
|
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
2018-02-09 19:29:02 +00:00
|
|
|
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
2016-07-05 14:21:21 +00:00
|
|
|
::testing::ValuesIn(std::vector<std::string>{
|
|
|
|
"OpStore %1 %2\n", // 3 words long.
|
|
|
|
"OpStore %1 %2 None\n", // 4 words long, explicit final 0.
|
2017-11-27 15:16:41 +00:00
|
|
|
"OpStore %1 %2 Volatile\n",
|
|
|
|
"OpStore %1 %2 Aligned 8\n",
|
2016-07-05 14:21:21 +00:00
|
|
|
"OpStore %1 %2 Nontemporal\n",
|
|
|
|
// Combinations show the names from LSB to MSB
|
|
|
|
"OpStore %1 %2 Volatile|Aligned 16\n",
|
|
|
|
"OpStore %1 %2 Volatile|Nontemporal\n",
|
|
|
|
"OpStore %1 %2 Volatile|Aligned|Nontemporal 32\n",
|
2019-01-29 23:56:52 +00:00
|
|
|
})));
|
2015-09-25 16:43:37 +00:00
|
|
|
|
2019-01-29 23:56:52 +00:00
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
2015-09-25 16:43:37 +00:00
|
|
|
FPFastMathModeMasks, RoundTripInstructionsTest,
|
2016-07-05 14:21:21 +00:00
|
|
|
Combine(
|
2017-03-14 16:43:41 +00:00
|
|
|
::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
2018-02-09 19:29:02 +00:00
|
|
|
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
2016-07-05 14:21:21 +00:00
|
|
|
::testing::ValuesIn(std::vector<std::string>{
|
|
|
|
"OpDecorate %1 FPFastMathMode None\n",
|
|
|
|
"OpDecorate %1 FPFastMathMode NotNaN\n",
|
|
|
|
"OpDecorate %1 FPFastMathMode NotInf\n",
|
|
|
|
"OpDecorate %1 FPFastMathMode NSZ\n",
|
|
|
|
"OpDecorate %1 FPFastMathMode AllowRecip\n",
|
|
|
|
"OpDecorate %1 FPFastMathMode Fast\n",
|
|
|
|
// Combinations show the names from LSB to MSB
|
|
|
|
"OpDecorate %1 FPFastMathMode NotNaN|NotInf\n",
|
|
|
|
"OpDecorate %1 FPFastMathMode NSZ|AllowRecip\n",
|
|
|
|
"OpDecorate %1 FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast\n",
|
2019-01-29 23:56:52 +00:00
|
|
|
})));
|
2016-07-05 14:21:21 +00:00
|
|
|
|
2019-01-29 23:56:52 +00:00
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
2018-02-09 19:29:02 +00:00
|
|
|
LoopControlMasks, RoundTripInstructionsTest,
|
|
|
|
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
|
|
|
SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_2),
|
|
|
|
::testing::ValuesIn(std::vector<std::string>{
|
|
|
|
"OpLoopMerge %1 %2 None\n",
|
|
|
|
"OpLoopMerge %1 %2 Unroll\n",
|
|
|
|
"OpLoopMerge %1 %2 DontUnroll\n",
|
|
|
|
"OpLoopMerge %1 %2 Unroll|DontUnroll\n",
|
2019-01-29 23:56:52 +00:00
|
|
|
})));
|
|
|
|
|
|
|
|
INSTANTIATE_TEST_SUITE_P(LoopControlMasksV11, RoundTripInstructionsTest,
|
|
|
|
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_1,
|
|
|
|
SPV_ENV_UNIVERSAL_1_2,
|
|
|
|
SPV_ENV_UNIVERSAL_1_3),
|
|
|
|
::testing::ValuesIn(std::vector<std::string>{
|
|
|
|
"OpLoopMerge %1 %2 DependencyInfinite\n",
|
|
|
|
"OpLoopMerge %1 %2 DependencyLength 8\n",
|
|
|
|
})));
|
|
|
|
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
2018-02-09 19:29:02 +00:00
|
|
|
SelectionControlMasks, RoundTripInstructionsTest,
|
|
|
|
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
|
|
|
SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_2),
|
|
|
|
::testing::ValuesIn(std::vector<std::string>{
|
|
|
|
"OpSelectionMerge %1 None\n",
|
|
|
|
"OpSelectionMerge %1 Flatten\n",
|
|
|
|
"OpSelectionMerge %1 DontFlatten\n",
|
|
|
|
"OpSelectionMerge %1 Flatten|DontFlatten\n",
|
2019-01-29 23:56:52 +00:00
|
|
|
})));
|
2015-09-25 16:43:37 +00:00
|
|
|
|
2019-01-29 23:56:52 +00:00
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
2018-02-09 19:29:02 +00:00
|
|
|
FunctionControlMasks, RoundTripInstructionsTest,
|
|
|
|
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
|
|
|
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
|
|
|
::testing::ValuesIn(std::vector<std::string>{
|
|
|
|
"%2 = OpFunction %1 None %3\n",
|
|
|
|
"%2 = OpFunction %1 Inline %3\n",
|
|
|
|
"%2 = OpFunction %1 DontInline %3\n",
|
|
|
|
"%2 = OpFunction %1 Pure %3\n",
|
|
|
|
"%2 = OpFunction %1 Const %3\n",
|
|
|
|
"%2 = OpFunction %1 Inline|Pure|Const %3\n",
|
|
|
|
"%2 = OpFunction %1 DontInline|Const %3\n",
|
2019-01-29 23:56:52 +00:00
|
|
|
})));
|
2016-07-05 14:21:21 +00:00
|
|
|
|
2019-01-29 23:56:52 +00:00
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
2015-09-25 16:43:37 +00:00
|
|
|
ImageMasks, RoundTripInstructionsTest,
|
2017-03-14 16:43:41 +00:00
|
|
|
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
2018-02-09 19:29:02 +00:00
|
|
|
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
2016-07-05 14:21:21 +00:00
|
|
|
::testing::ValuesIn(std::vector<std::string>{
|
|
|
|
"%2 = OpImageFetch %1 %3 %4\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 None\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 Bias %5\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 Lod %5\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 Grad %5 %6\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 ConstOffset %5\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 Offset %5\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 ConstOffsets %5\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 Sample %5\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 MinLod %5\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 Bias|Lod|Grad %5 %6 %7 %8\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 ConstOffset|Offset|ConstOffsets"
|
|
|
|
" %5 %6 %7\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4 Sample|MinLod %5 %6\n",
|
|
|
|
"%2 = OpImageFetch %1 %3 %4"
|
|
|
|
" Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample|MinLod"
|
2019-01-29 23:56:52 +00:00
|
|
|
" %5 %6 %7 %8 %9 %10 %11 %12 %13\n"})));
|
2015-09-25 16:43:37 +00:00
|
|
|
|
2019-01-29 23:56:52 +00:00
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
2017-03-14 16:43:41 +00:00
|
|
|
NewInstructionsInSPIRV1_2, RoundTripInstructionsTest,
|
2018-02-09 19:29:02 +00:00
|
|
|
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
2017-03-14 16:43:41 +00:00
|
|
|
::testing::ValuesIn(std::vector<std::string>{
|
|
|
|
"OpExecutionModeId %1 SubgroupsPerWorkgroupId %2\n",
|
|
|
|
"OpExecutionModeId %1 LocalSizeId %2 %3 %4\n",
|
|
|
|
"OpExecutionModeId %1 LocalSizeHintId %2\n",
|
|
|
|
"OpDecorateId %1 AlignmentId %2\n",
|
|
|
|
"OpDecorateId %1 MaxByteOffsetId %2\n",
|
2019-01-29 23:56:52 +00:00
|
|
|
})));
|
2017-03-14 16:43:41 +00:00
|
|
|
|
2015-11-12 15:45:36 +00:00
|
|
|
using MaskSorting = TextToBinaryTest;
|
2015-09-25 18:52:17 +00:00
|
|
|
|
|
|
|
TEST_F(MaskSorting, MasksAreSortedFromLSBToMSB) {
|
2015-10-22 17:24:41 +00:00
|
|
|
EXPECT_THAT(EncodeAndDecodeSuccessfully(
|
|
|
|
"OpStore %1 %2 Nontemporal|Aligned|Volatile 32"),
|
|
|
|
Eq("OpStore %1 %2 Volatile|Aligned|Nontemporal 32\n"));
|
2015-09-25 18:52:17 +00:00
|
|
|
EXPECT_THAT(
|
|
|
|
EncodeAndDecodeSuccessfully(
|
|
|
|
"OpDecorate %1 FPFastMathMode NotInf|Fast|AllowRecip|NotNaN|NSZ"),
|
2015-10-22 17:24:41 +00:00
|
|
|
Eq("OpDecorate %1 FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast\n"));
|
2015-09-25 18:52:17 +00:00
|
|
|
EXPECT_THAT(
|
|
|
|
EncodeAndDecodeSuccessfully("OpLoopMerge %1 %2 DontUnroll|Unroll"),
|
2015-10-22 17:24:41 +00:00
|
|
|
Eq("OpLoopMerge %1 %2 Unroll|DontUnroll\n"));
|
2015-09-25 18:52:17 +00:00
|
|
|
EXPECT_THAT(
|
|
|
|
EncodeAndDecodeSuccessfully("OpSelectionMerge %1 DontFlatten|Flatten"),
|
2015-10-22 17:24:41 +00:00
|
|
|
Eq("OpSelectionMerge %1 Flatten|DontFlatten\n"));
|
|
|
|
EXPECT_THAT(EncodeAndDecodeSuccessfully(
|
|
|
|
"%2 = OpFunction %1 DontInline|Const|Pure|Inline %3"),
|
|
|
|
Eq("%2 = OpFunction %1 Inline|DontInline|Pure|Const %3\n"));
|
2015-09-25 18:52:17 +00:00
|
|
|
EXPECT_THAT(EncodeAndDecodeSuccessfully(
|
|
|
|
"%2 = OpImageFetch %1 %3 %4"
|
|
|
|
" MinLod|Sample|Offset|Lod|Grad|ConstOffsets|ConstOffset|Bias"
|
|
|
|
" %5 %6 %7 %8 %9 %10 %11 %12 %13\n"),
|
2015-10-22 17:24:41 +00:00
|
|
|
Eq("%2 = OpImageFetch %1 %3 %4"
|
|
|
|
" Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample|MinLod"
|
|
|
|
" %5 %6 %7 %8 %9 %10 %11 %12 %13\n"));
|
2015-09-25 18:52:17 +00:00
|
|
|
}
|
|
|
|
|
2015-11-12 15:45:36 +00:00
|
|
|
using OperandTypeTest = TextToBinaryTest;
|
2015-11-10 19:29:35 +00:00
|
|
|
|
|
|
|
TEST_F(OperandTypeTest, OptionalTypedLiteralNumber) {
|
|
|
|
const std::string input =
|
|
|
|
"%1 = OpTypeInt 32 0\n"
|
|
|
|
"%2 = OpConstant %1 42\n"
|
|
|
|
"OpSwitch %2 %3 100 %4\n";
|
|
|
|
EXPECT_EQ(input, EncodeAndDecodeSuccessfully(input));
|
|
|
|
}
|
|
|
|
|
2015-11-12 18:53:27 +00:00
|
|
|
using IndentTest = spvtest::TextToBinaryTest;
|
|
|
|
|
|
|
|
TEST_F(IndentTest, Sample) {
|
|
|
|
const std::string input = R"(
|
|
|
|
OpCapability Shader
|
|
|
|
OpMemoryModel Logical GLSL450
|
|
|
|
%1 = OpTypeInt 32 0
|
|
|
|
%2 = OpTypeStruct %1 %3 %4 %5 %6 %7 %8 %9 %10 ; force IDs into double digits
|
|
|
|
%11 = OpConstant %1 42
|
|
|
|
OpStore %2 %3 Aligned|Volatile 4 ; bogus, but not indented
|
|
|
|
)";
|
|
|
|
const std::string expected =
|
|
|
|
R"( OpCapability Shader
|
|
|
|
OpMemoryModel Logical GLSL450
|
|
|
|
%1 = OpTypeInt 32 0
|
|
|
|
%2 = OpTypeStruct %1 %3 %4 %5 %6 %7 %8 %9 %10
|
|
|
|
%11 = OpConstant %1 42
|
|
|
|
OpStore %2 %3 Volatile|Aligned 4
|
|
|
|
)";
|
|
|
|
EXPECT_THAT(
|
|
|
|
EncodeAndDecodeSuccessfully(input, SPV_BINARY_TO_TEXT_OPTION_INDENT),
|
|
|
|
expected);
|
|
|
|
}
|
|
|
|
|
2016-07-08 18:29:52 +00:00
|
|
|
using FriendlyNameDisassemblyTest = spvtest::TextToBinaryTest;
|
|
|
|
|
|
|
|
TEST_F(FriendlyNameDisassemblyTest, Sample) {
|
|
|
|
const std::string input = R"(
|
|
|
|
OpCapability Shader
|
|
|
|
OpMemoryModel Logical GLSL450
|
|
|
|
%1 = OpTypeInt 32 0
|
|
|
|
%2 = OpTypeStruct %1 %3 %4 %5 %6 %7 %8 %9 %10 ; force IDs into double digits
|
|
|
|
%11 = OpConstant %1 42
|
|
|
|
)";
|
|
|
|
const std::string expected =
|
|
|
|
R"(OpCapability Shader
|
|
|
|
OpMemoryModel Logical GLSL450
|
|
|
|
%uint = OpTypeInt 32 0
|
|
|
|
%_struct_2 = OpTypeStruct %uint %3 %4 %5 %6 %7 %8 %9 %10
|
2016-10-13 20:22:04 +00:00
|
|
|
%uint_42 = OpConstant %uint 42
|
2016-07-08 18:29:52 +00:00
|
|
|
)";
|
|
|
|
EXPECT_THAT(EncodeAndDecodeSuccessfully(
|
|
|
|
input, SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES),
|
|
|
|
expected);
|
|
|
|
}
|
|
|
|
|
2016-01-18 20:29:15 +00:00
|
|
|
TEST_F(TextToBinaryTest, ShowByteOffsetsWhenRequested) {
|
|
|
|
const std::string input = R"(
|
|
|
|
OpCapability Shader
|
|
|
|
OpMemoryModel Logical GLSL450
|
|
|
|
%1 = OpTypeInt 32 0
|
|
|
|
%2 = OpTypeVoid
|
|
|
|
)";
|
|
|
|
const std::string expected =
|
|
|
|
R"(OpCapability Shader ; 0x00000014
|
|
|
|
OpMemoryModel Logical GLSL450 ; 0x0000001c
|
|
|
|
%1 = OpTypeInt 32 0 ; 0x00000028
|
|
|
|
%2 = OpTypeVoid ; 0x00000038
|
|
|
|
)";
|
|
|
|
EXPECT_THAT(EncodeAndDecodeSuccessfully(
|
|
|
|
input, SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET),
|
|
|
|
expected);
|
|
|
|
}
|
|
|
|
|
2015-11-13 00:40:21 +00:00
|
|
|
// Test version string.
|
|
|
|
TEST_F(TextToBinaryTest, VersionString) {
|
|
|
|
auto words = CompileSuccessfully("");
|
|
|
|
spv_text decoded_text = nullptr;
|
2016-04-19 02:25:35 +00:00
|
|
|
EXPECT_THAT(spvBinaryToText(ScopedContext().context, words.data(),
|
|
|
|
words.size(), SPV_BINARY_TO_TEXT_OPTION_NONE,
|
|
|
|
&decoded_text, &diagnostic),
|
2015-11-13 00:40:21 +00:00
|
|
|
Eq(SPV_SUCCESS));
|
|
|
|
EXPECT_EQ(nullptr, diagnostic);
|
|
|
|
|
2015-11-17 21:37:10 +00:00
|
|
|
EXPECT_THAT(decoded_text->str, HasSubstr("Version: 1.0\n"))
|
2015-11-13 00:40:21 +00:00
|
|
|
<< EncodeAndDecodeSuccessfully("");
|
|
|
|
spvTextDestroy(decoded_text);
|
|
|
|
}
|
|
|
|
|
2015-11-12 23:33:47 +00:00
|
|
|
// Test generator string.
|
|
|
|
|
|
|
|
// A test case for the generator string. This allows us to
|
|
|
|
// test both of the 16-bit components of the generator word.
|
|
|
|
struct GeneratorStringCase {
|
|
|
|
uint16_t generator;
|
|
|
|
uint16_t misc;
|
|
|
|
std::string expected;
|
|
|
|
};
|
|
|
|
|
|
|
|
using GeneratorStringTest = spvtest::TextToBinaryTestBase<
|
|
|
|
::testing::TestWithParam<GeneratorStringCase>>;
|
|
|
|
|
|
|
|
TEST_P(GeneratorStringTest, Sample) {
|
|
|
|
auto words = CompileSuccessfully("");
|
2015-11-18 14:22:10 +00:00
|
|
|
EXPECT_EQ(2u, SPV_INDEX_GENERATOR_NUMBER);
|
2015-11-12 23:33:47 +00:00
|
|
|
words[SPV_INDEX_GENERATOR_NUMBER] =
|
|
|
|
SPV_GENERATOR_WORD(GetParam().generator, GetParam().misc);
|
|
|
|
|
|
|
|
spv_text decoded_text = nullptr;
|
2016-04-19 02:25:35 +00:00
|
|
|
EXPECT_THAT(spvBinaryToText(ScopedContext().context, words.data(),
|
|
|
|
words.size(), SPV_BINARY_TO_TEXT_OPTION_NONE,
|
|
|
|
&decoded_text, &diagnostic),
|
2015-11-12 23:33:47 +00:00
|
|
|
Eq(SPV_SUCCESS));
|
|
|
|
EXPECT_THAT(diagnostic, Eq(nullptr));
|
|
|
|
EXPECT_THAT(std::string(decoded_text->str), HasSubstr(GetParam().expected));
|
|
|
|
spvTextDestroy(decoded_text);
|
|
|
|
}
|
|
|
|
|
2019-01-29 23:56:52 +00:00
|
|
|
INSTANTIATE_TEST_SUITE_P(GeneratorStrings, GeneratorStringTest,
|
|
|
|
::testing::ValuesIn(std::vector<GeneratorStringCase>{
|
|
|
|
{SPV_GENERATOR_KHRONOS, 12, "Khronos; 12"},
|
|
|
|
{SPV_GENERATOR_LUNARG, 99, "LunarG; 99"},
|
|
|
|
{SPV_GENERATOR_VALVE, 1, "Valve; 1"},
|
|
|
|
{SPV_GENERATOR_CODEPLAY, 65535, "Codeplay; 65535"},
|
|
|
|
{SPV_GENERATOR_NVIDIA, 19, "NVIDIA; 19"},
|
|
|
|
{SPV_GENERATOR_ARM, 1000, "ARM; 1000"},
|
|
|
|
{SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR, 38,
|
|
|
|
"Khronos LLVM/SPIR-V Translator; 38"},
|
|
|
|
{SPV_GENERATOR_KHRONOS_ASSEMBLER, 2,
|
|
|
|
"Khronos SPIR-V Tools Assembler; 2"},
|
|
|
|
{SPV_GENERATOR_KHRONOS_GLSLANG, 1,
|
|
|
|
"Khronos Glslang Reference Front End; 1"},
|
|
|
|
{1000, 18, "Unknown(1000); 18"},
|
|
|
|
{65535, 32767, "Unknown(65535); 32767"},
|
|
|
|
}));
|
2015-11-12 23:33:47 +00:00
|
|
|
|
2018-02-09 19:29:02 +00:00
|
|
|
// TODO(dneto): Test new instructions and enums in SPIR-V 1.3
|
|
|
|
|
2018-07-11 13:24:49 +00:00
|
|
|
} // namespace
|
|
|
|
} // namespace spvtools
|