case SPV_OPERAND_TYPE_DIMENSIONALITY:
case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE:
case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE:
- case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
case SPV_OPERAND_TYPE_FP_ROUNDING_MODE:
case SPV_OPERAND_TYPE_LINKAGE_TYPE:
case SPV_OPERAND_TYPE_ACCESS_QUALIFIER:
case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE:
case SPV_OPERAND_TYPE_DECORATION:
case SPV_OPERAND_TYPE_BUILT_IN:
- case SPV_OPERAND_TYPE_SELECTION_CONTROL:
- case SPV_OPERAND_TYPE_LOOP_CONTROL:
- case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
case SPV_OPERAND_TYPE_MEMORY_SEMANTICS:
- case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
case SPV_OPERAND_TYPE_EXECUTION_SCOPE:
case SPV_OPERAND_TYPE_GROUP_OPERATION:
case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS:
spvFixWord(words[0], endian), &entry)) {
DIAGNOSTIC << "Invalid " << spvOperandTypeStr(type) << " operand '"
<< words[0] << "'.";
- return SPV_ERROR_INVALID_TEXT;
+ return SPV_ERROR_INVALID_TEXT; // TODO(dneto): Surely this is invalid binary.
}
stream.get() << entry->name;
// Prepare to accept operands to this operand, if needed.
spvPrependOperandTypes(entry->operandTypes, pExpectedOperands);
position->index++;
} break;
+ case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
+ case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
+ case SPV_OPERAND_TYPE_LOOP_CONTROL:
+ case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
+ case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
+ case SPV_OPERAND_TYPE_SELECTION_CONTROL: {
+ // This operand is a mask.
+ // Scan it from least significant bit to most significant bit. For each
+ // set bit, emit the name of that bit and prepare to parse its operands,
+ // if any.
+ uint32_t remaining_word = spvFixWord(words[0], endian);
+ uint32_t mask;
+ int num_emitted = 0;
+ for (mask = 1; remaining_word; mask <<= 1) {
+ if (remaining_word & mask) {
+ remaining_word ^= mask;
+ spv_operand_desc entry;
+ if (spvOperandTableValueLookup(operandTable, type, mask, &entry)) {
+ DIAGNOSTIC << "Invalid " << spvOperandTypeStr(type) << " operand '"
+ << words[0] << "'.";
+ return SPV_ERROR_INVALID_BINARY;
+ }
+ if (num_emitted) stream.get() << "|";
+ stream.get() << entry->name;
+ num_emitted++;
+ }
+ }
+ if (!num_emitted) {
+ // An operand value of 0 was provided, so represent it by the name
+ // of the 0 value. In many cases, that's "None".
+ spv_operand_desc entry;
+ if (SPV_SUCCESS ==
+ spvOperandTableValueLookup(operandTable, type, 0, &entry)) {
+ stream.get() << entry->name;
+ // Prepare for its operands, if any.
+ spvPrependOperandTypes(entry->operandTypes, pExpectedOperands);
+ }
+ }
+ // Prepare for subsequent operands, if any.
+ // Scan from MSB to LSB since we can only prepend operands to a pattern.
+ remaining_word = spvFixWord(words[0], endian);
+ for (mask = (1u << 31); remaining_word; mask >>= 1) {
+ if (remaining_word & mask) {
+ remaining_word ^= mask;
+ spv_operand_desc entry;
+ if (SPV_SUCCESS ==
+ spvOperandTableValueLookup(operandTable, type, mask, &entry)) {
+ spvPrependOperandTypes(entry->operandTypes, pExpectedOperands);
+ }
+ }
+ }
+ position->index++;
+ } break;
default: {
DIAGNOSTIC << "Invalid binary operand '" << type << "'";
return SPV_ERROR_INVALID_BINARY;
#include "UnitSPIRV.h"
+#include "gmock/gmock.h"
+#include "TestFixture.h"
+
+using ::testing::Eq;
+
namespace {
class BinaryToText : public ::testing::Test {
spvTextDestroy(text);
}
+using RoundTripInstructionsTest =
+ spvtest::TextToBinaryTestBase<::testing::TestWithParam<std::string>>;
+
+TEST_P(RoundTripInstructionsTest, Sample) {
+ EXPECT_THAT(EncodeAndDecodeSuccessfully(GetParam()),
+ Eq(GetParam()));
+};
+
+// clang-format off
+INSTANTIATE_TEST_CASE_P(
+ MemoryAccessMasks, RoundTripInstructionsTest,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "OpStore %1 %2\n", // 3 words long.
+ "OpStore %1 %2 None\n", // 4 words long, explicit final 0.
+ "OpStore %1 %2 Volatile\n",
+ "OpStore %1 %2 Aligned 8\n",
+ "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",
+ }));
+// clang-format on
+
+INSTANTIATE_TEST_CASE_P(
+ FPFastMathModeMasks, RoundTripInstructionsTest,
+ ::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",
+ }));
+
+INSTANTIATE_TEST_CASE_P(LoopControlMasks, RoundTripInstructionsTest,
+ ::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",
+ }));
+
+INSTANTIATE_TEST_CASE_P(SelectionControlMasks, RoundTripInstructionsTest,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "OpSelectionMerge %1 None\n",
+ "OpSelectionMerge %1 Flatten\n",
+ "OpSelectionMerge %1 DontFlatten\n",
+ "OpSelectionMerge %1 Flatten|DontFlatten\n",
+ }));
+
+// clang-format off
+INSTANTIATE_TEST_CASE_P(
+ FunctionControlMasks, RoundTripInstructionsTest,
+ ::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",
+ }));
+// clang-format on
+
+// clang-format off
+INSTANTIATE_TEST_CASE_P(
+ ImageMasks, RoundTripInstructionsTest,
+ ::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"
+ " %5 %6 %7 %8 %9 %10 %11 %12 %13\n"}));
+// clang-format on
+
} // anonymous namespace