Add an API parameter to choose assembly syntax format for assembler.

Added a new enum for supported assembly syntax formats:
Canonical Assembly Format (CAF) and Assignment Assembly Format (AAF).

Updated assembler interface functions to support choice of assembly
syntax format.
This commit is contained in:
Lei Zhang 2015-09-10 14:00:00 -04:00 committed by David Neto
parent 92a225b371
commit 06efdc59e1
10 changed files with 278 additions and 131 deletions

View File

@ -162,6 +162,7 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES})
${CMAKE_CURRENT_SOURCE_DIR}/test/TestFixture.h
${CMAKE_CURRENT_SOURCE_DIR}/test/UnitSPIRV.h
${CMAKE_CURRENT_SOURCE_DIR}/test/AssemblyFormat.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/BinaryDestroy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/BinaryEndianness.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/BinaryHeaderGet.cpp

View File

@ -244,6 +244,12 @@ typedef enum spv_binary_to_text_options_t {
SPV_FORCE_32_BIT_ENUM(spv_binary_to_text_options_t)
} spv_binary_to_text_options_t;
typedef enum spv_assembly_syntax_format_t {
SPV_ASSEMBLY_SYNTAX_FORMAT_ASSIGNMENT, // Assignment Assembly Format
SPV_ASSEMBLY_SYNTAX_FORMAT_CANONICAL, // Canonical Assembly Format
SPV_ASSEMBLY_SYNTAX_FORMAT_DEFAULT = SPV_ASSEMBLY_SYNTAX_FORMAT_ASSIGNMENT,
} spv_assembly_syntax_format_t;
typedef enum spv_validate_options_t {
SPV_VALIDATE_BASIC_BIT = SPV_BIT(0),
SPV_VALIDATE_LAYOUT_BIT = SPV_BIT(1),
@ -412,13 +418,32 @@ spv_result_t spvExtInstTableGet(spv_ext_inst_table *pTable);
/// @param[out] pDiagnostic contains diagnostic on failure
///
/// @return result code
spv_result_t spvTextToBinary(const char* text,
const uint64_t length,
spv_result_t spvTextToBinary(const char *text, const uint64_t length,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
spv_binary *pBinary, spv_diagnostic *pDiagnostic);
/// @brief Entry point to covert text form to binary form
///
/// @param[in] text input text
/// @param[in] length of the input text
/// @param[in] format the assembly syntax format of text
/// @param[in] opcodeTable of specified Opcodes
/// @param[in] operandTable of specified operands
/// @param[in] extInstTable of specified extended instructions
/// @param[out] pBinary the binary module
/// @param[out] pDiagnostic contains diagnostic on failure
///
/// @return result code
spv_result_t spvTextWithFormatToBinary(const char *text, const uint64_t length,
spv_assembly_syntax_format_t format,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
spv_binary *pBinary,
spv_diagnostic *pDiagnostic);
/// @brief Free an allocated text stream
///
/// This is a no-op if the text parameter is a null pointer.

View File

@ -524,55 +524,64 @@ spv_result_t spvTextEncodeOperand(
}
spv_result_t spvTextEncodeOpcode(
const spv_text text, const spv_opcode_table opcodeTable,
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
spv_named_id_table namedIdTable, uint32_t *pBound, spv_instruction_t *pInst,
spv_position position, spv_diagnostic *pDiagnostic) {
const spv_text text, spv_assembly_syntax_format_t format,
const spv_opcode_table opcodeTable, const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable, spv_named_id_table namedIdTable,
uint32_t *pBound, spv_instruction_t *pInst, spv_position position,
spv_diagnostic *pDiagnostic) {
// An assembly instruction has two possible formats:
// 1. <opcode> <operand>.., e.g., "OpMemoryModel Physical64 OpenCL".
// 2. <result-id> = <opcode> <operand>.., e.g., "%void = OpTypeVoid".
// 1(CAF): <opcode> <operand>..., e.g., "OpTypeVoid %void".
// 2(AAF): <result-id> = <opcode> <operand>..., e.g., "%void = OpTypeVoid".
// Assume it's the first format at the beginning.
std::string opcodeName;
std::string firstWord;
spv_position_t nextPosition = {};
spv_result_t error =
spvTextWordGet(text, position, opcodeName, &nextPosition);
spv_result_t error = spvTextWordGet(text, position, firstWord, &nextPosition);
spvCheck(error, DIAGNOSTIC << "Internal Error"; return error);
// NOTE: Handle insertion of an immediate integer into the binary stream
if ('!' == text->str[position->index]) {
const char *begin = opcodeName.data() + 1;
const char *begin = firstWord.data() + 1;
char *end = nullptr;
uint32_t immediateInt = strtoul(begin, &end, 0);
size_t size = opcodeName.size() - 1;
size_t size = firstWord.size() - 1;
spvCheck(size != (size_t)(end - begin),
DIAGNOSTIC << "Invalid immediate integer '" << opcodeName << "'.";
DIAGNOSTIC << "Invalid immediate integer '" << firstWord << "'.";
return SPV_ERROR_INVALID_TEXT);
position->column += opcodeName.size();
position->index += opcodeName.size();
position->column += firstWord.size();
position->index += firstWord.size();
pInst->words[0] = immediateInt;
pInst->wordCount = 1;
return SPV_SUCCESS;
}
// Handle value generating instructions (the second format above) here.
std::string opcodeName;
std::string result_id;
spv_position_t result_id_position = {};
// If the word we get doesn't start with "Op", assume it's an <result-id>
// from now.
spvCheck(!spvStartsWithOp(text, position), result_id = opcodeName);
if (!result_id.empty()) {
if (spvStartsWithOp(text, position)) {
opcodeName = firstWord;
} else {
// If the first word of this instruction is not an opcode, we must be
// processing AAF now.
spvCheck(
SPV_ASSEMBLY_SYNTAX_FORMAT_ASSIGNMENT != format,
DIAGNOSTIC
<< "Expected <opcode> at the beginning of an instruction, found '"
<< firstWord << "'.";
return SPV_ERROR_INVALID_TEXT);
result_id = firstWord;
spvCheck('%' != result_id.front(),
DIAGNOSTIC << "Expected <opcode> or <result-id> at the beginning "
"of an instruction, found '"
<< result_id << "'.";
return SPV_ERROR_INVALID_TEXT);
result_id_position = *position;
// The '=' sign.
*position = nextPosition;
spvCheck(spvTextAdvance(text, position),
DIAGNOSTIC << "Expected '=', found end of stream.";
return SPV_ERROR_INVALID_TEXT);
// The '=' sign.
std::string equal_sign;
error = spvTextWordGet(text, position, equal_sign, &nextPosition);
spvCheck("=" != equal_sign, DIAGNOSTIC << "'=' expected after result id.";
@ -598,6 +607,14 @@ spv_result_t spvTextEncodeOpcode(
spvCheck(error, DIAGNOSTIC << "Invalid Opcode name '"
<< getWord(text->str + position->index) << "'";
return error);
if (SPV_ASSEMBLY_SYNTAX_FORMAT_ASSIGNMENT == format) {
// If this instruction has <result-id>, check it follows AAF.
spvCheck(opcodeEntry->hasResult && result_id.empty(),
DIAGNOSTIC << "Expected <result-id> at the beginning of an "
"instruction, found '"
<< firstWord << "'.";
return SPV_ERROR_INVALID_TEXT);
}
pInst->opcode = opcodeEntry->opcode;
*position = nextPosition;
pInst->wordCount++;
@ -669,7 +686,6 @@ spv_result_t spvTextEncodeOpcode(
spvCheck(error, return error);
*position = nextPosition;
}
}
@ -684,6 +700,7 @@ namespace {
// If a diagnostic is generated, it is not yet marked as being
// for a text-based input.
spv_result_t spvTextToBinaryInternal(const spv_text text,
spv_assembly_syntax_format_t format,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
@ -716,9 +733,9 @@ spv_result_t spvTextToBinaryInternal(const spv_text text,
spv_instruction_t inst = {};
inst.extInstType = extInstType;
spvCheck(spvTextEncodeOpcode(text, opcodeTable, operandTable, extInstTable,
namedIdTable, &bound, &inst, &position,
pDiagnostic),
spvCheck(spvTextEncodeOpcode(text, format, opcodeTable, operandTable,
extInstTable, namedIdTable, &bound, &inst,
&position, pDiagnostic),
spvNamedIdTableDestory(namedIdTable);
return SPV_ERROR_INVALID_TEXT);
extInstType = inst.extInstType;
@ -758,16 +775,27 @@ spv_result_t spvTextToBinaryInternal(const spv_text text,
} // anonymous namespace
spv_result_t spvTextToBinary(const char* input_text,
spv_result_t spvTextToBinary(const char *input_text,
const uint64_t input_text_size,
const spv_opcode_table opcodeTable,
const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable,
spv_binary *pBinary, spv_diagnostic *pDiagnostic) {
return spvTextWithFormatToBinary(
input_text, input_text_size, SPV_ASSEMBLY_SYNTAX_FORMAT_DEFAULT,
opcodeTable, operandTable, extInstTable, pBinary, pDiagnostic);
}
spv_result_t spvTextWithFormatToBinary(
const char *input_text, const uint64_t input_text_size,
spv_assembly_syntax_format_t format, const spv_opcode_table opcodeTable,
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
spv_binary *pBinary, spv_diagnostic *pDiagnostic) {
spv_text_t text = {input_text, input_text_size};
spv_result_t result = spvTextToBinaryInternal(
&text, opcodeTable, operandTable, extInstTable, pBinary, pDiagnostic);
spv_result_t result =
spvTextToBinaryInternal(&text, format, opcodeTable, operandTable,
extInstTable, pBinary, pDiagnostic);
if (pDiagnostic && *pDiagnostic) (*pDiagnostic)->isTextSource = true;
return result;

View File

@ -191,6 +191,7 @@ spv_result_t spvTextEncodeOperand(
/// @brief Translate single Opcode and operands to binary form
///
/// @param[in] text stream to translate
/// @param[in] format the assembly syntax format of text
/// @param[in] opcodeTable Opcode lookup table
/// @param[in] operandTable operand lookup table
/// @param[in,out] namedIdTable table of named ID's
@ -201,9 +202,10 @@ spv_result_t spvTextEncodeOperand(
///
/// @return result code
spv_result_t spvTextEncodeOpcode(
const spv_text text, const spv_opcode_table opcodeTable,
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
spv_named_id_table namedIdTable, uint32_t *pBound, spv_instruction_t *pInst,
spv_position_t *pPosition, spv_diagnostic *pDiagnostic);
const spv_text text, spv_assembly_syntax_format_t format,
const spv_opcode_table opcodeTable, const spv_operand_table operandTable,
const spv_ext_inst_table extInstTable, spv_named_id_table namedIdTable,
uint32_t *pBound, spv_instruction_t *pInst, spv_position_t *pPosition,
spv_diagnostic *pDiagnostic);
#endif

109
test/AssemblyFormat.cpp Normal file
View File

@ -0,0 +1,109 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include "TestFixture.h"
namespace {
using test_fixture::TextToBinaryTest;
TEST_F(TextToBinaryTest, EncodeAAFTextAsAAF) {
SetText("%2 = OpConstant %1 1000");
EXPECT_EQ(SPV_SUCCESS,
spvTextWithFormatToBinary(
text.str, text.length, SPV_ASSEMBLY_SYNTAX_FORMAT_ASSIGNMENT,
opcodeTable, operandTable, extInstTable, &binary, &diagnostic));
if (diagnostic) {
spvDiagnosticPrint(diagnostic);
}
}
TEST_F(TextToBinaryTest, EncodeAAFTextAsCAF) {
SetText("%2 = OpConstant %1 1000");
EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
spvTextWithFormatToBinary(
text.str, text.length, SPV_ASSEMBLY_SYNTAX_FORMAT_CANONICAL,
opcodeTable, operandTable, extInstTable, &binary, &diagnostic));
ASSERT_TRUE(diagnostic);
EXPECT_STREQ(
"Expected <opcode> at the beginning of an instruction, found '%2'.",
diagnostic->error);
EXPECT_EQ(0, diagnostic->position.line);
}
TEST_F(TextToBinaryTest, EncodeCAFTextAsCAF) {
SetText("OpConstant %1 %2 1000");
EXPECT_EQ(SPV_SUCCESS,
spvTextWithFormatToBinary(
text.str, text.length, SPV_ASSEMBLY_SYNTAX_FORMAT_CANONICAL,
opcodeTable, operandTable, extInstTable, &binary, &diagnostic));
if (diagnostic) {
spvDiagnosticPrint(diagnostic);
}
}
TEST_F(TextToBinaryTest, EncodeCAFTextAsAAF) {
SetText("OpConstant %1 %2 1000");
EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
spvTextWithFormatToBinary(
text.str, text.length, SPV_ASSEMBLY_SYNTAX_FORMAT_ASSIGNMENT,
opcodeTable, operandTable, extInstTable, &binary, &diagnostic));
ASSERT_TRUE(diagnostic);
EXPECT_STREQ(
"Expected <result-id> at the beginning of an instruction, found "
"'OpConstant'.",
diagnostic->error);
EXPECT_EQ(0, diagnostic->position.line);
}
TEST_F(TextToBinaryTest, EncodeMixedTextAsAAF) {
SetText("OpConstant %1 %2 1000\n%3 = OpConstant %1 2000");
EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
spvTextWithFormatToBinary(
text.str, text.length, SPV_ASSEMBLY_SYNTAX_FORMAT_ASSIGNMENT,
opcodeTable, operandTable, extInstTable, &binary, &diagnostic));
ASSERT_TRUE(diagnostic);
EXPECT_STREQ(
"Expected <result-id> at the beginning of an instruction, found "
"'OpConstant'.",
diagnostic->error);
EXPECT_EQ(0, diagnostic->position.line);
}
TEST_F(TextToBinaryTest, EncodeMixedTextAsCAF) {
SetText("OpConstant %1 %2 1000\n%3 = OpConstant %1 2000");
EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
spvTextWithFormatToBinary(
text.str, text.length, SPV_ASSEMBLY_SYNTAX_FORMAT_CANONICAL,
opcodeTable, operandTable, extInstTable, &binary, &diagnostic));
ASSERT_TRUE(diagnostic);
EXPECT_STREQ(
"Expected <opcode> at the beginning of an instruction, found '%3'.",
diagnostic->error);
EXPECT_EQ(1, diagnostic->position.line);
}
} // anonymous namespace

View File

@ -62,15 +62,15 @@ TEST_F(TextToBinaryTest, ImmediateIntOperand) {
using ImmediateIntTest = TextToBinaryTest;
TEST_F(ImmediateIntTest, AnyWordInSimpleStatement) {
const SpirvVector original = CompileSuccessfully("OpConstant %1 %2 123");
const SpirvVector original = CompileCAFSuccessfully("OpConstant %1 %2 123");
// TODO(deki): uncomment assertions below and make them pass.
// EXPECT_EQ(original, CompileSuccessfully("!0x0004002B %1 %2 123"));
EXPECT_EQ(original, CompileSuccessfully("OpConstant !1 %2 123"));
// EXPECT_EQ(original, CompileSuccessfully("OpConstant %1 !2 123"));
EXPECT_EQ(original, CompileSuccessfully("OpConstant %1 %2 !123"));
// EXPECT_EQ(original, CompileSuccessfully("!0x0004002B %1 !2 123"));
EXPECT_EQ(original, CompileSuccessfully("OpConstant !1 %2 !123"));
// EXPECT_EQ(original, CompileSuccessfully("!0x0004002B !1 !2 !123"));
// EXPECT_EQ(original, CompileCAFSuccessfully("!0x0004002B %1 %2 123"));
EXPECT_EQ(original, CompileCAFSuccessfully("OpConstant !1 %2 123"));
// EXPECT_EQ(original, CompileCAFSuccessfully("OpConstant %1 !2 123"));
EXPECT_EQ(original, CompileCAFSuccessfully("OpConstant %1 %2 !123"));
// EXPECT_EQ(original, CompileCAFSuccessfully("!0x0004002B %1 !2 123"));
EXPECT_EQ(original, CompileCAFSuccessfully("OpConstant !1 %2 !123"));
// EXPECT_EQ(original, CompileCAFSuccessfully("!0x0004002B !1 !2 !123"));
}
TEST_F(ImmediateIntTest, AnyWordInAssignmentStatement) {
@ -90,37 +90,37 @@ TEST_F(ImmediateIntTest, AnyWordInAssignmentStatement) {
// Literal integers after !<integer> are handled correctly.
TEST_F(ImmediateIntTest, IntegerFollowingImmediate) {
const SpirvVector original = CompileSuccessfully("OpTypeInt %1 8 1");
const SpirvVector original = CompileCAFSuccessfully("OpTypeInt %1 8 1");
// TODO(deki): uncomment assertions below and make them pass.
// EXPECT_EQ(original, CompileSuccessfully("!0x00040015 1 8 1"));
// EXPECT_EQ(original, CompileSuccessfully("OpTypeInt !1 8 1"));
// EXPECT_EQ(original, CompileCAFSuccessfully("!0x00040015 1 8 1"));
// EXPECT_EQ(original, CompileCAFSuccessfully("OpTypeInt !1 8 1"));
// 64-bit integer literal.
EXPECT_EQ(CompileSuccessfully("OpConstant %10 %1 5000000000"),
CompileSuccessfully("OpConstant %10 !1 5000000000"));
EXPECT_EQ(CompileCAFSuccessfully("OpConstant %10 %1 5000000000"),
CompileCAFSuccessfully("OpConstant %10 !1 5000000000"));
// Negative integer.
EXPECT_EQ(CompileSuccessfully("OpConstant %10 %1 -123"),
CompileSuccessfully("OpConstant %10 !1 -123"));
EXPECT_EQ(CompileCAFSuccessfully("OpConstant %10 %1 -123"),
CompileCAFSuccessfully("OpConstant %10 !1 -123"));
// Hex value(s).
// EXPECT_EQ(CompileSuccessfully("OpConstant %10 %1 0x12345678"),
// CompileSuccessfully("OpConstant %10 !1 0x12345678"));
// EXPECT_EQ(CompileSuccessfully("OpConstant %10 %1 0x12345678 0x87654321"),
// CompileSuccessfully("OpConstant %10 !1 0x12345678 0x87654321"));
// EXPECT_EQ(CompileCAFSuccessfully("OpConstant %10 %1 0x12345678"),
// CompileCAFSuccessfully("OpConstant %10 !1 0x12345678"));
// EXPECT_EQ(CompileCAFSuccessfully("OpConstant %10 %1 0x12345678 0x87654321"),
// CompileCAFSuccessfully("OpConstant %10 !1 0x12345678 0x87654321"));
}
// Literal floats after !<integer> are handled correctly.
TEST_F(ImmediateIntTest, FloatFollowingImmediate) {
EXPECT_EQ(CompileSuccessfully("OpConstant %10 %1 0.123"),
CompileSuccessfully("OpConstant %10 !1 0.123"));
EXPECT_EQ(CompileSuccessfully("OpConstant %10 %1 -0.5"),
CompileSuccessfully("OpConstant %10 !1 -0.5"));
EXPECT_EQ(CompileCAFSuccessfully("OpConstant %10 %1 0.123"),
CompileCAFSuccessfully("OpConstant %10 !1 0.123"));
EXPECT_EQ(CompileCAFSuccessfully("OpConstant %10 %1 -0.5"),
CompileCAFSuccessfully("OpConstant %10 !1 -0.5"));
// 64-bit float.
EXPECT_EQ(
CompileSuccessfully(
CompileCAFSuccessfully(
"OpConstant %10 %1 9999999999999999999999999999999999999999.9"),
CompileSuccessfully(
CompileCAFSuccessfully(
"OpConstant %10 !1 9999999999999999999999999999999999999999.9"));
}
@ -129,12 +129,11 @@ TEST_F(ImmediateIntTest, StringFollowingImmediate) {
// Try a variety of strings, including empty and single-character.
for (std::string name : {"", "s", "longish"}) {
const SpirvVector original =
CompileSuccessfully("OpMemberName %10 4 \"" + name + "\"");
CompileCAFSuccessfully("OpMemberName %10 4 \"" + name + "\"");
EXPECT_EQ(original,
CompileSuccessfully("OpMemberName %10 !4 \"" + name + "\""));
CompileCAFSuccessfully("OpMemberName %10 !4 \"" + name + "\""));
// TODO(deki): uncomment assertions below and make them pass.
// EXPECT_EQ(original,
// CompileSuccessfully("!0x00040006 !10 4 \"" + name + "\""));
// EXPECT_EQ(original, CompileCAFSuccessfully("!0x00040006 !10 4 \"" + name + "\""));
}
}
@ -142,40 +141,41 @@ TEST_F(ImmediateIntTest, StringFollowingImmediate) {
TEST_F(ImmediateIntTest, IdFollowingImmediate) {
// TODO(deki): uncomment assertions below and make them pass.
#if 0
EXPECT_EQ(CompileSuccessfully("OpDecorationGroup %123"),
CompileSuccessfully("!0x00020049 %123"));
EXPECT_EQ(CompileSuccessfully("OpDecorationGroup %group"),
CompileSuccessfully("!0x00020049 %group"));
EXPECT_EQ(CompileCAFSuccessfully("OpDecorationGroup %123"),
CompileCAFSuccessfully("!0x00020049 %123"));
EXPECT_EQ(CompileCAFSuccessfully("OpDecorationGroup %group"),
CompileCAFSuccessfully("!0x00020049 %group"));
#endif
}
// !<integer> after !<integer> is handled correctly.
TEST_F(ImmediateIntTest, ImmediateFollowingImmediate) {
const SpirvVector original = CompileSuccessfully("OpTypeMatrix %11 %10 7");
EXPECT_EQ(original, CompileSuccessfully("OpTypeMatrix %11 !10 !7"));
const SpirvVector original = CompileCAFSuccessfully("OpTypeMatrix %11 %10 7");
EXPECT_EQ(original, CompileCAFSuccessfully("OpTypeMatrix %11 !10 !7"));
// TODO(deki): uncomment assertions below and make them pass.
// EXPECT_EQ(original, CompileSuccessfully("!0x00040018 %11 !10 !7"));
// EXPECT_EQ(original, CompileCAFSuccessfully("!0x00040018 %11 !10 !7"));
}
TEST_F(ImmediateIntTest, InvalidStatement) {
EXPECT_THAT(Subvector(CompileSuccessfully("!4 !3 !2 !1"), kFirstInstruction),
ElementsAre(4, 3, 2, 1));
EXPECT_THAT(
Subvector(CompileCAFSuccessfully("!4 !3 !2 !1"), kFirstInstruction),
ElementsAre(4, 3, 2, 1));
}
TEST_F(ImmediateIntTest, InvalidStatementBetweenValidOnes) {
EXPECT_THAT(
Subvector(CompileSuccessfully("OpTypeFloat %10 32 !5 !6 !7 OpEmitVertex"),
kFirstInstruction),
ElementsAre(spvOpcodeMake(3, spv::OpTypeFloat), 10, 32, 5, 6, 7,
spvOpcodeMake(1, spv::OpEmitVertex)));
EXPECT_THAT(Subvector(CompileCAFSuccessfully(
"OpTypeFloat %10 32 !5 !6 !7 OpEmitVertex"),
kFirstInstruction),
ElementsAre(spvOpcodeMake(3, spv::OpTypeFloat), 10, 32, 5, 6, 7,
spvOpcodeMake(1, spv::OpEmitVertex)));
}
TEST_F(ImmediateIntTest, NextOpcodeRecognized) {
const SpirvVector original = CompileSuccessfully(R"(
const SpirvVector original = CompileCAFSuccessfully(R"(
OpLoad %10 %1 %2 Volatile
OpCompositeInsert %11 %4 %1 %3 0 1 2
)");
const SpirvVector alternate = CompileSuccessfully(R"(
const SpirvVector alternate = CompileCAFSuccessfully(R"(
OpLoad %10 %1 %2 !1
OpCompositeInsert %11 %4 %1 %3 0 1 2
)");
@ -183,13 +183,13 @@ OpCompositeInsert %11 %4 %1 %3 0 1 2
}
TEST_F(ImmediateIntTest, WrongLengthButNextOpcodeStillRecognized) {
const SpirvVector original = CompileSuccessfully(R"(
const SpirvVector original = CompileCAFSuccessfully(R"(
OpLoad %10 %1 %2 Volatile
OpCopyMemorySized %3 %4 %1
)");
// TODO(deki): uncomment assertions below and make them pass.
#if 0
const SpirvVector alternate = CompileSuccessfully(R"(
const SpirvVector alternate = CompileCAFSuccessfully(R"(
!0x0002003D %10 %1 %2 !1
OpCopyMemorySized %3 %4 %1
)");
@ -200,13 +200,15 @@ OpCopyMemorySized %3 %4 %1
}
// Like NextOpcodeRecognized, but next statement is in assignment form.
TEST_F(ImmediateIntTest, NextAssignmentRecognized) {
// TODO(deki): enable this after adding proper support for !<integer> at the
// beginning of an instruction.
TEST_F(ImmediateIntTest, DISABLED_NextAssignmentRecognized) {
const SpirvVector original = CompileSuccessfully(R"(
OpLoad %10 %1 %2 None
%1 = OpLoad %10 %2 None
%4 = OpFunctionCall %10 %3 123
)");
const SpirvVector alternate = CompileSuccessfully(R"(
OpLoad %10 !1 %2 !0
!1 = OpLoad %10 %2 !0
%4 = OpFunctionCall %10 %3 123
)");
EXPECT_EQ(original, alternate);
@ -215,8 +217,8 @@ OpLoad %10 !1 %2 !0
// Two instructions in a row each have !<integer> opcode.
TEST_F(ImmediateIntTest, ConsecutiveImmediateOpcodes) {
const SpirvVector original = CompileSuccessfully(R"(
OpConstantSampler %10 %1 Clamp 78 Linear
OpFRem %11 %4 %3 %2
%1 = OpConstantSampler %10 Clamp 78 Linear
%4 = OpFRem %11 %3 %2
%5 = OpIsValidEvent %12 %2
)");
// TODO(deki): uncomment assertions below and make them pass.

View File

@ -65,12 +65,13 @@ class TextToBinaryTestBase : public T {
return SpirvVector(v.begin() + from, v.end());
}
// Compiles SPIR-V text, asserting compilation success. Returns the compiled
// code.
SpirvVector CompileSuccessfully(const std::string& text) {
spv_result_t status =
spvTextToBinary(text.c_str(), text.size(), opcodeTable, operandTable,
extInstTable, &binary, &diagnostic);
// Compiles SPIR-V text in the given assembly syntax format, asserting
// compilation success. Returns the compiled code.
SpirvVector CompileWithFormatSuccessfully(
const std::string& text, spv_assembly_syntax_format_t format) {
spv_result_t status = spvTextWithFormatToBinary(
text.c_str(), text.size(), format, opcodeTable, operandTable,
extInstTable, &binary, &diagnostic);
EXPECT_EQ(SPV_SUCCESS, status) << text;
SpirvVector code_copy;
if (status == SPV_SUCCESS) {
@ -81,6 +82,18 @@ class TextToBinaryTestBase : public T {
}
return code_copy;
}
// Compiles SPIR-V text in the Assignment Assembly Format, asserting success.
// Returns the compiled code.
SpirvVector CompileSuccessfully(const std::string& text) {
return CompileWithFormatSuccessfully(text,
SPV_ASSEMBLY_SYNTAX_FORMAT_ASSIGNMENT);
}
// Compiles SPIR-V text in the Canonical Assembly Format, asserting success.
// Returns the compiled code.
SpirvVector CompileCAFSuccessfully(const std::string& text) {
return CompileWithFormatSuccessfully(text,
SPV_ASSEMBLY_SYNTAX_FORMAT_CANONICAL);
}
// Compiles SPIR-V text, asserting compilation failure. Returns the error
// message(s).

View File

@ -28,9 +28,7 @@
namespace {
TEST(TextDestroy, DestroyNull) {
spvBinaryDestroy(nullptr);
}
TEST(TextDestroy, DestroyNull) { spvBinaryDestroy(nullptr); }
TEST(TextDestroy, Default) {
spv_opcode_table opcodeTable;
@ -67,8 +65,9 @@ TEST(TextDestroy, Default) {
spv_binary binary = nullptr;
spv_diagnostic diagnostic = nullptr;
EXPECT_EQ(SPV_SUCCESS,
spvTextToBinary(textStr, strlen(textStr), opcodeTable, operandTable,
extInstTable, &binary, &diagnostic));
spvTextWithFormatToBinary(
textStr, strlen(textStr), SPV_ASSEMBLY_SYNTAX_FORMAT_CANONICAL,
opcodeTable, operandTable, extInstTable, &binary, &diagnostic));
EXPECT_NE(nullptr, binary);
EXPECT_NE(nullptr, binary->code);
EXPECT_NE(0, binary->wordCount);

View File

@ -262,37 +262,6 @@ TEST_F(TextToBinaryTest, StringSpace) {
}
}
// TODO(antiagainst): we might not want to support both instruction formats in
// the future. Only the "<result-id> = <opcode> <operand>.." one may survive.
TEST_F(TextToBinaryTest, InstructionTwoFormats) {
SetText(R"(
OpCapability Shader
%glsl450 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical Simple
OpTypeBool %3
%4 = OpTypeInt 8 0
OpTypeInt %5 8 1
%6 = OpTypeInt 16 0
OpTypeInt %7 16 1
%void = OpTypeVoid
OpTypeFloat %float 32
%const1.5 = OpConstant %float 1.5
OpTypeFunction %fnMain %void
%main = OpFunction %void None %fnMain
OpLabel %lbMain
%result = OpExtInst $float $glsl450 Round $const1.5
OpReturn
OpFunctionEnd
)");
EXPECT_EQ(SPV_SUCCESS,
spvTextToBinary(text.str, text.length, opcodeTable, operandTable,
extInstTable, &binary, &diagnostic));
if (diagnostic) {
spvDiagnosticPrint(diagnostic);
}
}
TEST_F(TextToBinaryTest, UnknownBeginningOfInstruction) {
SetText(R"(
OpSource OpenCL 12
@ -357,8 +326,7 @@ TEST_F(TextToBinaryTest, WrongOpCode) {
}
TEST_F(TextToBinaryTest, GoodSwitch) {
const SpirvVector code = CompileSuccessfully(
R"(
const SpirvVector code = CompileSuccessfully(R"(
%i32 = OpTypeInt 32 0
%fortytwo = OpConstant %i32 42
%twelve = OpConstant %i32 12

View File

@ -411,7 +411,7 @@ TEST_F(ValidateID, OpConstantTrueBad) {
TEST_F(ValidateID, OpConstantFalseGood) {
const char *spirv = R"(
OpTypeBool %1
%1 = OpTypeBool
%2 = OpConstantTrue %1)";
CHECK(spirv, SPV_SUCCESS);
}