mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-25 04:50:04 +00:00
All values now represent symbolic names instead of mixed with numeric.
Also removed un-necessary heap-allocation of spv_named_id_table. This removed the necessity to expose a function to create/destroy it and simplified the interface.
This commit is contained in:
parent
a66952d38c
commit
13804e5d63
148
source/text.cpp
148
source/text.cpp
@ -28,6 +28,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@ -47,9 +48,7 @@ using spvutils::BitwiseCast;
|
||||
|
||||
// Structures
|
||||
|
||||
struct spv_named_id_table_t {
|
||||
std::unordered_map<std::string, uint32_t> namedIds;
|
||||
};
|
||||
using spv_named_id_table = std::unordered_map<std::string, uint32_t>;
|
||||
|
||||
// Text API
|
||||
|
||||
@ -72,39 +71,12 @@ std::string spvGetWord(const char *str) {
|
||||
return ""; // Make certain compilers happy.
|
||||
}
|
||||
|
||||
spv_named_id_table spvNamedIdTableCreate() {
|
||||
return new spv_named_id_table_t();
|
||||
}
|
||||
|
||||
void spvNamedIdTableDestory(spv_named_id_table table) { delete table; }
|
||||
|
||||
uint32_t spvNamedIdAssignOrGet(spv_named_id_table table, const char *textValue,
|
||||
uint32_t spvNamedIdAssignOrGet(spv_named_id_table* table, const char *textValue,
|
||||
uint32_t *pBound) {
|
||||
if (table->namedIds.end() == table->namedIds.find(textValue)) {
|
||||
table->namedIds[textValue] = *pBound;
|
||||
if (table->end() == table->find(textValue)) {
|
||||
(*table)[std::string(textValue)] = *pBound;
|
||||
}
|
||||
return table->namedIds[textValue];
|
||||
}
|
||||
|
||||
int32_t spvTextIsNamedId(const char *textValue) {
|
||||
// TODO: Strengthen the parsing of textValue to only include allow names that
|
||||
// match: ([a-z]|[A-Z])(_|[a-z]|[A-Z]|[0-9])*
|
||||
switch (textValue[0]) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
return (*table)[textValue];
|
||||
}
|
||||
|
||||
spv_result_t spvTextAdvanceLine(const spv_text text, spv_position position) {
|
||||
@ -125,6 +97,22 @@ spv_result_t spvTextAdvanceLine(const spv_text text, spv_position position) {
|
||||
}
|
||||
}
|
||||
|
||||
bool spvIsValidIDCharacter(const char value) {
|
||||
return value == '_' || 0 != ::isalnum(value);
|
||||
}
|
||||
|
||||
// Returns true if the given string represents a valid ID name.
|
||||
bool spvIsValidID(const char* textValue) {
|
||||
const char* c = textValue;
|
||||
for (; *c != '\0'; ++c) {
|
||||
if (!spvIsValidIDCharacter(*c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If the string was empty, then the ID also is not valid.
|
||||
return c != textValue;
|
||||
}
|
||||
|
||||
spv_result_t spvTextAdvance(const spv_text text, spv_position position) {
|
||||
// NOTE: Consume white space, otherwise don't advance.
|
||||
switch (text->str[position->index]) {
|
||||
@ -409,10 +397,25 @@ spv_result_t spvTextParseMaskOperand(const spv_operand_table operandTable,
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Translate an Opcode operand to binary form
|
||||
///
|
||||
/// @param[in] type of the operand
|
||||
/// @param[in] textValue word of text to be parsed
|
||||
/// @param[in] operandTable operand lookup table
|
||||
/// @param[in,out] namedIdTable table of named ID's
|
||||
/// @param[out] pInst return binary Opcode
|
||||
/// @param[in,out] pExpectedOperands the operand types expected
|
||||
/// @param[in,out] pBound current highest defined ID value
|
||||
/// @param[in] pPosition used in diagnostic on error
|
||||
/// @param[out] pDiagnostic populated on error
|
||||
///
|
||||
/// @return result code
|
||||
spv_result_t spvTextEncodeOperand(
|
||||
const spv_operand_type_t type, const char *textValue,
|
||||
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
|
||||
spv_named_id_table namedIdTable, spv_instruction_t *pInst,
|
||||
spv_named_id_table* namedIdTable, spv_instruction_t *pInst,
|
||||
spv_operand_pattern_t *pExpectedOperands, uint32_t *pBound,
|
||||
const spv_position position, spv_diagnostic *pDiagnostic) {
|
||||
// NOTE: Handle immediate int in the stream
|
||||
@ -430,7 +433,6 @@ spv_result_t spvTextEncodeOperand(
|
||||
position->index += size;
|
||||
pInst->words[pInst->wordCount] = immediateInt;
|
||||
pInst->wordCount += 1;
|
||||
if (isIdType(type)) *pBound = std::max(*pBound, immediateInt + 1);
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
@ -442,22 +444,16 @@ spv_result_t spvTextEncodeOperand(
|
||||
case SPV_OPERAND_TYPE_EXECUTION_SCOPE: {
|
||||
if ('%' == textValue[0]) {
|
||||
textValue++;
|
||||
}
|
||||
// TODO: Force all ID's to be prefixed with '%'.
|
||||
uint32_t id = 0;
|
||||
if (spvTextIsNamedId(textValue)) {
|
||||
id = spvNamedIdAssignOrGet(namedIdTable, textValue, pBound);
|
||||
} else {
|
||||
if (spvTextToUInt32(textValue, &id) != SPV_SUCCESS) {
|
||||
if (spvOperandIsOptional(type)) {
|
||||
return SPV_FAILED_MATCH;
|
||||
} else {
|
||||
DIAGNOSTIC << "Invalid " << spvOperandTypeStr(type) << " '"
|
||||
<< textValue << "'.";
|
||||
return SPV_ERROR_INVALID_TEXT;
|
||||
}
|
||||
}
|
||||
DIAGNOSTIC << "Expected id to start with %.";
|
||||
return SPV_ERROR_INVALID_TEXT;
|
||||
}
|
||||
if (!spvIsValidID(textValue)) {
|
||||
DIAGNOSTIC << "Invalid ID " << textValue;
|
||||
return SPV_ERROR_INVALID_TEXT;
|
||||
}
|
||||
const uint32_t id =
|
||||
spvNamedIdAssignOrGet(namedIdTable, textValue, pBound);
|
||||
pInst->words[pInst->wordCount++] = id;
|
||||
*pBound = std::max(*pBound, id + 1);
|
||||
} break;
|
||||
@ -609,7 +605,7 @@ namespace {
|
||||
/// leaves position pointing to the error in text.
|
||||
spv_result_t encodeInstructionStartingWithImmediate(
|
||||
const spv_text text, const spv_operand_table operandTable,
|
||||
const spv_ext_inst_table extInstTable, spv_named_id_table namedIdTable,
|
||||
const spv_ext_inst_table extInstTable, spv_named_id_table* namedIdTable,
|
||||
uint32_t *pBound, spv_instruction_t *pInst, spv_position position,
|
||||
spv_diagnostic *pDiagnostic) {
|
||||
std::string firstWord;
|
||||
@ -684,10 +680,23 @@ spv_result_t encodeInstructionStartingWithImmediate(
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/// @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
|
||||
/// @param[in,out] pBound current highest defined ID value
|
||||
/// @param[out] pInst returned binary Opcode
|
||||
/// @param[in,out] pPosition in the text stream
|
||||
/// @param[out] pDiagnostic populated on failure
|
||||
///
|
||||
/// @return result code
|
||||
spv_result_t spvTextEncodeOpcode(
|
||||
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,
|
||||
const spv_ext_inst_table extInstTable, spv_named_id_table* namedIdTable,
|
||||
uint32_t *pBound, spv_instruction_t *pInst, spv_position position,
|
||||
spv_diagnostic *pDiagnostic) {
|
||||
|
||||
@ -898,29 +907,28 @@ spv_result_t spvTextToBinaryInternal(const spv_text text,
|
||||
return SPV_ERROR_INVALID_TEXT;
|
||||
}
|
||||
|
||||
spv_named_id_table namedIdTable = spvNamedIdTableCreate();
|
||||
if (!namedIdTable) return SPV_ERROR_OUT_OF_MEMORY;
|
||||
// This causes namedIdTable to get cleaned up as soon as it is no
|
||||
// longer necessary.
|
||||
{
|
||||
spv_named_id_table namedIdTable;
|
||||
spv_ext_inst_type_t extInstType = SPV_EXT_INST_TYPE_NONE;
|
||||
while (text->length > position.index) {
|
||||
spv_instruction_t inst = {};
|
||||
inst.extInstType = extInstType;
|
||||
|
||||
spv_ext_inst_type_t extInstType = SPV_EXT_INST_TYPE_NONE;
|
||||
while (text->length > position.index) {
|
||||
spv_instruction_t inst = {};
|
||||
inst.extInstType = extInstType;
|
||||
if (spvTextEncodeOpcode(text, format, opcodeTable, operandTable,
|
||||
extInstTable, &namedIdTable, &bound, &inst,
|
||||
&position, pDiagnostic)) {
|
||||
return SPV_ERROR_INVALID_TEXT;
|
||||
}
|
||||
extInstType = inst.extInstType;
|
||||
|
||||
if (spvTextEncodeOpcode(text, format, opcodeTable, operandTable,
|
||||
extInstTable, namedIdTable, &bound, &inst,
|
||||
&position, pDiagnostic)) {
|
||||
spvNamedIdTableDestory(namedIdTable);
|
||||
return SPV_ERROR_INVALID_TEXT;
|
||||
instructions.push_back(inst);
|
||||
|
||||
if (spvTextAdvance(text, &position)) break;
|
||||
}
|
||||
extInstType = inst.extInstType;
|
||||
|
||||
instructions.push_back(inst);
|
||||
|
||||
if (spvTextAdvance(text, &position)) break;
|
||||
}
|
||||
|
||||
spvNamedIdTableDestory(namedIdTable);
|
||||
|
||||
size_t totalSize = SPV_INDEX_INSTRUCTION;
|
||||
for (auto &inst : instructions) {
|
||||
totalSize += inst.wordCount;
|
||||
|
@ -58,11 +58,6 @@ typedef struct spv_literal_t {
|
||||
} value;
|
||||
} spv_literal_t;
|
||||
|
||||
struct spv_named_id_table_t;
|
||||
|
||||
// Types
|
||||
|
||||
typedef spv_named_id_table_t *spv_named_id_table;
|
||||
|
||||
// Functions
|
||||
|
||||
@ -151,33 +146,6 @@ spv_result_t spvTextToUInt32(const char *textValue, uint32_t *pValue);
|
||||
/// @return result code
|
||||
spv_result_t spvTextToLiteral(const char *textValue, spv_literal_t *pLiteral);
|
||||
|
||||
/// @brief Create a named ID table
|
||||
///
|
||||
/// @return named ID table
|
||||
spv_named_id_table spvNamedIdTableCreate();
|
||||
|
||||
/// @brief Free a named ID table
|
||||
///
|
||||
/// @param table named ID table
|
||||
void spvNamedIdTableDestory(spv_named_id_table table);
|
||||
|
||||
/// @brief Lookup or assign a named ID
|
||||
///
|
||||
/// @param table named ID table
|
||||
/// @param textValue name value
|
||||
/// @param pBound upper ID bound, used for assigning new ID's
|
||||
///
|
||||
/// @return the new ID assossiated with the named ID
|
||||
uint32_t spvNamedIdAssignOrGet(spv_named_id_table table, const char *textValue,
|
||||
uint32_t *pBound);
|
||||
|
||||
/// @brief Determine if a name has an assossiated ID
|
||||
///
|
||||
/// @param textValue name value
|
||||
///
|
||||
/// @return zero on failure, non-zero otherwise
|
||||
int32_t spvTextIsNamedId(const char *textValue);
|
||||
|
||||
/// @brief Parses a mask expression string for the given operand type.
|
||||
///
|
||||
/// A mask expression is a sequence of one or more terms separated by '|',
|
||||
@ -195,45 +163,4 @@ int32_t spvTextIsNamedId(const char *textValue);
|
||||
spv_result_t spvTextParseMaskOperand(const spv_operand_table operandTable,
|
||||
const spv_operand_type_t type,
|
||||
const char *textValue, uint32_t *pValue);
|
||||
|
||||
/// @brief Translate an Opcode operand to binary form
|
||||
///
|
||||
/// @param[in] type of the operand
|
||||
/// @param[in] textValue word of text to be parsed
|
||||
/// @param[in] operandTable operand lookup table
|
||||
/// @param[in,out] namedIdTable table of named ID's
|
||||
/// @param[out] pInst return binary Opcode
|
||||
/// @param[in,out] pExpectedOperands the operand types expected
|
||||
/// @param[in,out] pBound current highest defined ID value
|
||||
/// @param[in] pPosition used in diagnostic on error
|
||||
/// @param[out] pDiagnostic populated on error
|
||||
///
|
||||
/// @return result code
|
||||
spv_result_t spvTextEncodeOperand(
|
||||
const spv_operand_type_t type, const char *textValue,
|
||||
const spv_operand_table operandTable, const spv_ext_inst_table extInstTable,
|
||||
spv_named_id_table namedIdTable, spv_instruction_t *pInst,
|
||||
spv_operand_pattern_t *pExpectedOperands, uint32_t *pBound,
|
||||
const spv_position_t *pPosition, spv_diagnostic *pDiagnostic);
|
||||
|
||||
/// @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
|
||||
/// @param[in,out] pBound current highest defined ID value
|
||||
/// @param[out] pInst returned binary Opcode
|
||||
/// @param[in,out] pPosition in the text stream
|
||||
/// @param[out] pDiagnostic populated on failure
|
||||
///
|
||||
/// @return result code
|
||||
spv_result_t spvTextEncodeOpcode(
|
||||
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
|
||||
|
14
syntax.md
14
syntax.md
@ -75,12 +75,12 @@ An ID definition pertains to the `<result-id>` of an OpCode, and ID usage is any
|
||||
input to an OpCode. All IDs are prefixed with `%`. To differentiate between
|
||||
defs and uses, we suggest using the second format shown in the above example.
|
||||
|
||||
## Named IDs
|
||||
|
||||
The assembler also supports named IDs, or virtual IDs, which greatly improves
|
||||
the readability of the assembly. The same ID definition and usage prefixes
|
||||
apply. Names must begin with an character in the range `[a-z|A-Z]`. The
|
||||
following example will result in identical SPIR-V binary as the example above.
|
||||
The ID names do not necessarily have to be numerical. Furthermore to avoid
|
||||
aliasing names, if a name is numerical, it will not necessarily map to the
|
||||
corresponding numerical id in the generated spirv. The same ID definition and
|
||||
usage prefixes apply. Names may contain any character in
|
||||
['0-9|a-z|A-Z|\_'] The following example will result in identical SPIR-V binary
|
||||
as the example above.
|
||||
|
||||
```
|
||||
OpCapability Shader
|
||||
@ -95,6 +95,8 @@ following example will result in identical SPIR-V binary as the example above.
|
||||
OpFunctionEnd
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Arbitrary Integers
|
||||
<a name="immediate"></a>
|
||||
|
||||
|
@ -57,7 +57,7 @@ class BinaryToText : public ::testing::Test {
|
||||
%12 = OpTypeFloat 16
|
||||
%13 = OpTypeFloat 32
|
||||
%14 = OpTypeFloat 64
|
||||
%15 = OpTypeVector 4 2
|
||||
%15 = OpTypeVector %4 2
|
||||
)";
|
||||
spv_text_t text = {textStr, strlen(textStr)};
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
|
@ -69,8 +69,8 @@ OpEntryPoint Vertex %2 "main"
|
||||
"\n" + std::string(GetParam().constGenInst) + R"(
|
||||
%6 = OpTypeFunction %3
|
||||
%2 = OpFunction %3 None %6
|
||||
%8 = OpLabel
|
||||
%9 = OpExtInst )" + GetParam().extInstRetType +
|
||||
%7 = OpLabel
|
||||
%8 = OpExtInst )" + GetParam().extInstRetType +
|
||||
" %1 " + GetParam().extInstOpName + " " +
|
||||
GetParam().extInstOperandVars + R"(
|
||||
OpReturn
|
||||
@ -80,7 +80,7 @@ OpFunctionEnd
|
||||
R"(; SPIR-V
|
||||
; Version: 99
|
||||
; Generator: Khronos
|
||||
; Bound: 10
|
||||
; Bound: 9
|
||||
; Schema: 0)";
|
||||
spv_binary binary;
|
||||
spv_diagnostic diagnostic;
|
||||
@ -100,7 +100,7 @@ OpFunctionEnd
|
||||
// the generated SPIR-V binary.
|
||||
std::vector<uint32_t> expected_contains(
|
||||
{12 /*OpExtInst*/ | GetParam().extInstLength << 16, 4 /*return type*/,
|
||||
9 /*result id*/, 1 /*glsl450 import*/, GetParam().extInstOpcode});
|
||||
8 /*result id*/, 1 /*glsl450 import*/, GetParam().extInstOpcode});
|
||||
for (uint32_t operand : GetParam().extInstOperandIds) {
|
||||
expected_contains.push_back(operand);
|
||||
}
|
||||
|
@ -34,8 +34,10 @@
|
||||
|
||||
namespace {
|
||||
|
||||
using spvtest::MakeInstruction;
|
||||
using spvtest::TextToBinaryTest;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Eq;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::StrEq;
|
||||
|
||||
@ -66,27 +68,34 @@ TEST_F(TextToBinaryTest, ImmediateIntOperand) {
|
||||
using ImmediateIntTest = TextToBinaryTest;
|
||||
|
||||
TEST_F(ImmediateIntTest, AnyWordInSimpleStatement) {
|
||||
const SpirvVector original =
|
||||
CompileSuccessfully("OpConstant %1 %2 123", kCAF);
|
||||
// TODO(deki): uncomment assertions below and make them pass.
|
||||
EXPECT_EQ(original, CompileSuccessfully("!0x0004002B %1 %2 123", kCAF));
|
||||
EXPECT_EQ(original, CompileSuccessfully("OpConstant !1 %2 123", kCAF));
|
||||
EXPECT_EQ(original, CompileSuccessfully("OpConstant %1 !2 123", kCAF));
|
||||
EXPECT_EQ(original, CompileSuccessfully("OpConstant %1 %2 !123", kCAF));
|
||||
EXPECT_THAT(CompiledInstructions("!0x0004002B %a %b 123", kCAF),
|
||||
Eq(MakeInstruction(spv::OpConstant, {1, 2, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("OpConstant !1 %b 123", kCAF),
|
||||
Eq(MakeInstruction(spv::OpConstant, {1, 1, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("OpConstant %1 !2 123", kCAF),
|
||||
Eq(MakeInstruction(spv::OpConstant, {1, 2, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("OpConstant %a %b !123", kCAF),
|
||||
Eq(MakeInstruction(spv::OpConstant, {1, 2, 123})));
|
||||
// EXPECT_EQ(original, CompileSuccessfully("!0x0004002B %1 !2 123", kCAF));
|
||||
EXPECT_EQ(original, CompileSuccessfully("OpConstant !1 %2 !123", kCAF));
|
||||
EXPECT_THAT(CompiledInstructions("OpConstant !1 %b !123", kCAF),
|
||||
Eq(MakeInstruction(spv::OpConstant, {1, 1, 123})));
|
||||
// EXPECT_EQ(original, CompileSuccessfully("!0x0004002B !1 !2 !123", kCAF));
|
||||
}
|
||||
|
||||
TEST_F(ImmediateIntTest, AnyWordAfterEqualsAndOpCode) {
|
||||
const SpirvVector original =
|
||||
CompileSuccessfully("%2 = OpArrayLength %12 %1 123");
|
||||
EXPECT_EQ(original, CompileSuccessfully("%2 = OpArrayLength !12 %1 123"));
|
||||
EXPECT_EQ(original, CompileSuccessfully("%2 = OpArrayLength %12 !1 123"));
|
||||
EXPECT_EQ(original, CompileSuccessfully("%2 = OpArrayLength %12 %1 !123"));
|
||||
EXPECT_EQ(original, CompileSuccessfully("%2 = OpArrayLength %12 !1 !123"));
|
||||
EXPECT_EQ(original, CompileSuccessfully("%2 = OpArrayLength !12 !1 123"));
|
||||
EXPECT_EQ(original, CompileSuccessfully("%2 = OpArrayLength !12 !1 !123"));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength !2 %c 123"),
|
||||
Eq(MakeInstruction(spv::OpArrayLength, {2, 1, 2, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength %b !3 123"),
|
||||
Eq(MakeInstruction(spv::OpArrayLength, {1, 2, 3, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength %b %c !123"),
|
||||
Eq(MakeInstruction(spv::OpArrayLength, {1, 2, 3, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength %b !3 !123"),
|
||||
Eq(MakeInstruction(spv::OpArrayLength, {1, 2, 3, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength !2 !3 123"),
|
||||
Eq(MakeInstruction(spv::OpArrayLength, {2, 1, 3, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength !2 !3 !123"),
|
||||
Eq(MakeInstruction(spv::OpArrayLength, {2, 1, 3, 123})));
|
||||
}
|
||||
|
||||
TEST_F(ImmediateIntTest, ResultIdInAssignment) {
|
||||
@ -103,19 +112,19 @@ TEST_F(ImmediateIntTest, OpCodeInAssignment) {
|
||||
|
||||
// Literal integers after !<integer> are handled correctly.
|
||||
TEST_F(ImmediateIntTest, IntegerFollowingImmediate) {
|
||||
const SpirvVector original = CompileSuccessfully(
|
||||
const SpirvVector original = CompiledInstructions(
|
||||
"OpTypeInt %1 8 1", kCAF);
|
||||
// TODO(deki): uncomment assertions below and make them pass.
|
||||
// EXPECT_EQ(original, CompileSuccessfully("!0x00040015 1 8 1", kCAF));
|
||||
EXPECT_EQ(original, CompileSuccessfully("OpTypeInt !1 8 1", kCAF));
|
||||
EXPECT_EQ(original, CompiledInstructions("OpTypeInt !1 8 1", kCAF));
|
||||
|
||||
// 64-bit integer literal.
|
||||
EXPECT_EQ(CompileSuccessfully("OpConstant %10 %1 5000000000", kCAF),
|
||||
CompileSuccessfully("OpConstant %10 !1 5000000000", kCAF));
|
||||
EXPECT_EQ(CompiledInstructions("OpConstant %10 %2 5000000000", kCAF),
|
||||
CompiledInstructions("OpConstant %10 !2 5000000000", kCAF));
|
||||
|
||||
// Negative integer.
|
||||
EXPECT_EQ(CompileSuccessfully("OpConstant %10 %1 -123", kCAF),
|
||||
CompileSuccessfully("OpConstant %10 !1 -123", kCAF));
|
||||
EXPECT_EQ(CompiledInstructions("OpConstant %10 %2 -123", kCAF),
|
||||
CompiledInstructions("OpConstant %10 !2 -123", kCAF));
|
||||
|
||||
// Hex value(s).
|
||||
// EXPECT_EQ(CompileSuccessfully("OpConstant %10 %1 0x12345678", kCAF),
|
||||
@ -127,16 +136,16 @@ TEST_F(ImmediateIntTest, IntegerFollowingImmediate) {
|
||||
|
||||
// Literal floats after !<integer> are handled correctly.
|
||||
TEST_F(ImmediateIntTest, FloatFollowingImmediate) {
|
||||
EXPECT_EQ(CompileSuccessfully("OpConstant %10 %1 0.123", kCAF),
|
||||
CompileSuccessfully("OpConstant %10 !1 0.123", kCAF));
|
||||
EXPECT_EQ(CompileSuccessfully("OpConstant %10 %1 -0.5", kCAF),
|
||||
CompileSuccessfully("OpConstant %10 !1 -0.5", kCAF));
|
||||
EXPECT_EQ(CompiledInstructions("OpConstant %10 %2 0.123", kCAF),
|
||||
CompiledInstructions("OpConstant %10 !2 0.123", kCAF));
|
||||
EXPECT_EQ(CompiledInstructions("OpConstant %10 %2 -0.5", kCAF),
|
||||
CompiledInstructions("OpConstant %10 !2 -0.5", kCAF));
|
||||
// 64-bit float.
|
||||
EXPECT_EQ(
|
||||
CompileSuccessfully(
|
||||
"OpConstant %10 %1 9999999999999999999999999999999999999999.9", kCAF),
|
||||
CompileSuccessfully(
|
||||
"OpConstant %10 !1 9999999999999999999999999999999999999999.9",
|
||||
CompiledInstructions(
|
||||
"OpConstant %10 %2 9999999999999999999999999999999999999999.9", kCAF),
|
||||
CompiledInstructions(
|
||||
"OpConstant %10 !2 9999999999999999999999999999999999999999.9",
|
||||
kCAF));
|
||||
}
|
||||
|
||||
@ -145,17 +154,18 @@ TEST_F(ImmediateIntTest, StringFollowingImmediate) {
|
||||
// Try a variety of strings, including empty and single-character.
|
||||
for (std::string name : {"", "s", "longish", "really looooooooooooooooong"}) {
|
||||
const SpirvVector original =
|
||||
CompileSuccessfully("OpMemberName %10 4 \"" + name + "\"", kCAF);
|
||||
EXPECT_EQ(original,
|
||||
CompileSuccessfully("OpMemberName %10 !4 \"" + name + "\"", kCAF))
|
||||
CompiledInstructions("OpMemberName %10 4 \"" + name + "\"", kCAF);
|
||||
EXPECT_EQ(original, CompiledInstructions(
|
||||
"OpMemberName %10 !4 \"" + name + "\"", kCAF))
|
||||
<< name;
|
||||
EXPECT_EQ(original,
|
||||
CompileSuccessfully("OpMemberName !10 !4 \"" + name + "\"", kCAF))
|
||||
CompiledInstructions("OpMemberName !1 !4 \"" + name + "\"", kCAF))
|
||||
<< name;
|
||||
const uint32_t wordCount = 4 + name.size() / 4;
|
||||
const uint32_t firstWord = spvOpcodeMake(wordCount, spv::OpMemberName);
|
||||
EXPECT_EQ(original, CompileSuccessfully("!" + std::to_string(firstWord) +
|
||||
" %10 !4 \"" + name + "\"", kCAF))
|
||||
EXPECT_EQ(original, CompiledInstructions("!" + std::to_string(firstWord) +
|
||||
" %10 !4 \"" + name + "\"",
|
||||
kCAF))
|
||||
<< name;
|
||||
}
|
||||
}
|
||||
@ -171,9 +181,9 @@ TEST_F(ImmediateIntTest, IdFollowingImmediate) {
|
||||
// !<integer> after !<integer> is handled correctly.
|
||||
TEST_F(ImmediateIntTest, ImmediateFollowingImmediate) {
|
||||
const SpirvVector original =
|
||||
CompileSuccessfully("OpTypeMatrix %11 %10 7", kCAF);
|
||||
EXPECT_EQ(original, CompileSuccessfully("OpTypeMatrix %11 !10 !7", kCAF));
|
||||
EXPECT_EQ(original, CompileSuccessfully("!0x00040018 %11 !10 !7", kCAF));
|
||||
CompiledInstructions("OpTypeMatrix %a %b 7", kCAF);
|
||||
EXPECT_EQ(original, CompiledInstructions("OpTypeMatrix %a !2 !7", kCAF));
|
||||
EXPECT_EQ(original, CompiledInstructions("!0x00040018 %a !2 !7", kCAF));
|
||||
}
|
||||
|
||||
TEST_F(ImmediateIntTest, InvalidStatement) {
|
||||
@ -186,7 +196,7 @@ TEST_F(ImmediateIntTest, InvalidStatementBetweenValidOnes) {
|
||||
EXPECT_THAT(Subvector(CompileSuccessfully(
|
||||
"OpTypeFloat %10 32 !5 !6 !7 OpEmitVertex", kCAF),
|
||||
kFirstInstruction),
|
||||
ElementsAre(spvOpcodeMake(3, spv::OpTypeFloat), 10, 32, 5, 6, 7,
|
||||
ElementsAre(spvOpcodeMake(3, spv::OpTypeFloat), 1, 32, 5, 6, 7,
|
||||
spvOpcodeMake(1, spv::OpEmitVertex)));
|
||||
}
|
||||
|
||||
@ -224,11 +234,11 @@ OpCopyMemorySized %3 %4 %1
|
||||
TEST_F(ImmediateIntTest, NextAssignmentRecognized) {
|
||||
const SpirvVector original = CompileSuccessfully(R"(
|
||||
%1 = OpLoad %10 %2 None
|
||||
%4 = OpFunctionCall %10 %3 123
|
||||
%4 = OpFunctionCall %10 %3 %123
|
||||
)");
|
||||
const SpirvVector alternate = CompileSuccessfully(R"(
|
||||
%1 = OpLoad %10 %2 !0
|
||||
%4 = OpFunctionCall %10 %3 123
|
||||
%4 = OpFunctionCall %10 %3 %123
|
||||
)");
|
||||
EXPECT_EQ(original, alternate);
|
||||
}
|
||||
|
@ -25,6 +25,9 @@
|
||||
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
#include "UnitSPIRV.h"
|
||||
#include "TestFixture.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
@ -72,4 +75,58 @@ TEST(NamedId, Default) {
|
||||
spvBinaryDestroy(binary);
|
||||
}
|
||||
|
||||
struct IdCheckCase {
|
||||
std::string id;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
using IdValidityTest =
|
||||
spvtest::TextToBinaryTestBase<::testing::TestWithParam<IdCheckCase>>;
|
||||
|
||||
TEST_P(IdValidityTest, IdTypes) {
|
||||
std::string input = GetParam().id + " = OpTypeVoid";
|
||||
SetText(input);
|
||||
if (GetParam().valid) {
|
||||
CompileSuccessfully(input);
|
||||
} else {
|
||||
CompileFailure(input);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
ValidAndInvalidIds, IdValidityTest,
|
||||
::testing::ValuesIn(std::vector<IdCheckCase>({{"%1", true},
|
||||
{"%2abc", true},
|
||||
{"%3Def", true},
|
||||
{"%4GHI", true},
|
||||
{"%5_j_k", true},
|
||||
{"%6J_M", true},
|
||||
{"%n", true},
|
||||
{"%O", true},
|
||||
{"%p7", true},
|
||||
{"%Q8", true},
|
||||
{"%R_S", true},
|
||||
{"%T_10_U", true},
|
||||
{"%V_11", true},
|
||||
{"%W_X_13", true},
|
||||
{"%_A", true},
|
||||
{"%_", true},
|
||||
{"%__", true},
|
||||
{"%A_", true},
|
||||
{"%_A_", true},
|
||||
|
||||
{"%@", false},
|
||||
{"%!", false},
|
||||
{"%ABC!", false},
|
||||
{"%__A__@", false},
|
||||
{"%%", false},
|
||||
{"%-", false},
|
||||
{"%foo_@_bar", false},
|
||||
{"%", false},
|
||||
|
||||
{"5", false},
|
||||
{"32", false},
|
||||
{"foo", false},
|
||||
{"a%bar", false}})));
|
||||
|
||||
} // anonymous namespace
|
||||
|
@ -129,8 +129,9 @@ class TextToBinaryTestBase : public T {
|
||||
|
||||
// Compiles SPIR-V text, asserts success, and returns the words representing
|
||||
// the instructions. In particular, skip the words in the SPIR-V header.
|
||||
SpirvVector CompiledInstructions(const std::string& text) {
|
||||
const SpirvVector code = CompileSuccessfully(text);
|
||||
SpirvVector CompiledInstructions(const std::string& text,
|
||||
spv_assembly_syntax_format_t format) {
|
||||
const SpirvVector code = CompileSuccessfully(text, format);
|
||||
SpirvVector result;
|
||||
// Extract just the instructions.
|
||||
// If the code fails to compile, then return the empty vector.
|
||||
@ -140,6 +141,13 @@ class TextToBinaryTestBase : public T {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Compiles SPIR-V text with the default assembly format, asserts success, and
|
||||
// returns the words representing the instructions. In particular, skip the
|
||||
// words in the SPIR-V header.
|
||||
SpirvVector CompiledInstructions(const std::string& text) {
|
||||
return CompiledInstructions(text, SPV_ASSEMBLY_SYNTAX_FORMAT_DEFAULT);
|
||||
}
|
||||
|
||||
void SetText(const std::string& code) {
|
||||
textString = code;
|
||||
text.str = textString.c_str();
|
||||
|
@ -44,22 +44,22 @@ TEST(TextDestroy, Default) {
|
||||
OpSource OpenCL 12
|
||||
OpMemoryModel Physical64 OpenCL
|
||||
OpSourceExtension "PlaceholderExtensionName"
|
||||
OpEntryPoint Kernel 0 ""
|
||||
OpExecutionMode 0 LocalSizeHint 1 1 1
|
||||
OpTypeVoid 1
|
||||
OpTypeBool 2
|
||||
OpTypeInt 3 8 0
|
||||
OpTypeInt 4 8 1
|
||||
OpTypeInt 5 16 0
|
||||
OpTypeInt 6 16 1
|
||||
OpTypeInt 7 32 0
|
||||
OpTypeInt 8 32 1
|
||||
OpTypeInt 9 64 0
|
||||
OpTypeInt 10 64 1
|
||||
OpTypeFloat 11 16
|
||||
OpTypeFloat 12 32
|
||||
OpTypeFloat 13 64
|
||||
OpTypeVector 14 3 2
|
||||
OpEntryPoint Kernel %0 ""
|
||||
OpExecutionMode %0 LocalSizeHint 1 1 1
|
||||
OpTypeVoid %1
|
||||
OpTypeBool %2
|
||||
OpTypeInt %3 8 0
|
||||
OpTypeInt %4 8 1
|
||||
OpTypeInt %5 16 0
|
||||
OpTypeInt %6 16 1
|
||||
OpTypeInt %7 32 0
|
||||
OpTypeInt %8 32 1
|
||||
OpTypeInt %9 64 0
|
||||
OpTypeInt %10 64 1
|
||||
OpTypeFloat %11 16
|
||||
OpTypeFloat %12 32
|
||||
OpTypeFloat %13 64
|
||||
OpTypeVector %14 %3 2
|
||||
)";
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
|
@ -70,12 +70,12 @@ INSTANTIATE_TEST_CASE_P(
|
||||
{"", {}},
|
||||
// Test each kind, alone.
|
||||
{"Bias %5", {MASK(Bias), 5}},
|
||||
{"Lod %10", {MASK(Lod), 10}},
|
||||
{"Grad %11 %12", {MASK(Grad), 11, 12}},
|
||||
{"ConstOffset %13", {MASK(ConstOffset), 13}},
|
||||
{"Offset %14", {MASK(Offset), 14}},
|
||||
{"ConstOffsets %15", {MASK(ConstOffsets), 15}},
|
||||
{"Sample %16", {MASK(Sample), 16}},
|
||||
{"Lod %10", {MASK(Lod), 5}},
|
||||
{"Grad %11 %12", {MASK(Grad), 5, 6}},
|
||||
{"ConstOffset %13", {MASK(ConstOffset), 5}},
|
||||
{"Offset %14", {MASK(Offset), 5}},
|
||||
{"ConstOffsets %15", {MASK(ConstOffsets), 5}},
|
||||
{"Sample %16", {MASK(Sample), 5}},
|
||||
}));
|
||||
#undef MASK
|
||||
#define MASK(NAME) static_cast<uint32_t>(spv::ImageOperands##NAME##Mask)
|
||||
@ -85,28 +85,28 @@ INSTANTIATE_TEST_CASE_P(
|
||||
// TODO(dneto): Rev32 adds many more values, and rearranges their
|
||||
// values.
|
||||
// Test adjacent pairs, so we can easily debug the values when it fails.
|
||||
{"Bias|Lod %10 %11", {MASK(Bias) | MASK(Lod), 10, 11}},
|
||||
{"Lod|Grad %12 %13 %14", {MASK(Lod) | MASK(Grad), 12, 13, 14}},
|
||||
{"Bias|Lod %10 %11", {MASK(Bias) | MASK(Lod), 5, 6}},
|
||||
{"Lod|Grad %12 %13 %14", {MASK(Lod) | MASK(Grad), 5, 6, 7}},
|
||||
{"Grad|ConstOffset %15 %16 %17",
|
||||
{MASK(Grad) | MASK(ConstOffset), 15, 16, 17}},
|
||||
{MASK(Grad) | MASK(ConstOffset), 5, 6, 7}},
|
||||
{"ConstOffset|Offset %18 %19",
|
||||
{MASK(ConstOffset) | MASK(Offset), 18, 19}},
|
||||
{MASK(ConstOffset) | MASK(Offset), 5, 6}},
|
||||
{"Offset|ConstOffsets %20 %21",
|
||||
{MASK(Offset) | MASK(ConstOffsets), 20, 21}},
|
||||
{MASK(Offset) | MASK(ConstOffsets), 5, 6}},
|
||||
{"ConstOffsets|Sample %22 %23",
|
||||
{MASK(ConstOffsets) | MASK(Sample), 22, 23}},
|
||||
{MASK(ConstOffsets) | MASK(Sample), 5, 6}},
|
||||
// Test all masks together.
|
||||
{"Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample"
|
||||
" %5 %10 %11 %12 %13 %14 %15 %16",
|
||||
{MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) |
|
||||
MASK(Offset) | MASK(ConstOffsets) | MASK(Sample),
|
||||
5, 10, 11, 12, 13, 14, 15, 16}},
|
||||
5, 6, 7, 8, 9, 10, 11, 12}},
|
||||
// The same, but with mask value names reversed.
|
||||
{"Sample|ConstOffsets|Offset|ConstOffset|Grad|Lod|Bias"
|
||||
" %5 %10 %11 %12 %13 %14 %15 %16",
|
||||
{MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) |
|
||||
MASK(Offset) | MASK(ConstOffsets) | MASK(Sample),
|
||||
5, 10, 11, 12, 13, 14, 15, 16}}}));
|
||||
5, 6, 7, 8, 9, 10, 11, 12}}}));
|
||||
#undef MASK
|
||||
|
||||
} // anonymous namespace
|
||||
|
@ -81,7 +81,7 @@ using StorageClassTest = spvtest::TextToBinaryTestBase<
|
||||
TEST_P(StorageClassTest, AnyStorageClass) {
|
||||
std::string input = "%1 = OpVariable %2 " + GetParam().name();
|
||||
EXPECT_THAT(CompiledInstructions(input),
|
||||
Eq(MakeInstruction(spv::OpVariable, {2, 1, GetParam().value()})));
|
||||
Eq(MakeInstruction(spv::OpVariable, {1, 2, GetParam().value()})));
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
|
@ -152,7 +152,7 @@ TEST(TextToBinary, Default) {
|
||||
%12 = OpTypeFloat 16
|
||||
%13 = OpTypeFloat 32
|
||||
%14 = OpTypeFloat 64
|
||||
%15 = OpTypeVector 4 2
|
||||
%15 = OpTypeVector %4 2
|
||||
)";
|
||||
|
||||
spv_opcode_table opcodeTable;
|
||||
|
Loading…
Reference in New Issue
Block a user