Enforce suitable literal number operands to be unsigned integers.

Except for OpConstant and OpSpecConstant, all other literal number
operands are indeed unsigned integers. So,

* Rename all *LITERAL_NUMBER* operand types to *LITERAL_INTEGER*.
* Expect unsigned integers for *LITERAL_INTEGER* operands.
* Keep MULITPLE_WORD_LITERAL untouched since it is only used by
  OpConstant and OpSpecConstant.

And we want to provide the capability to specify floating-point
numbers after !<integer> in the alternate parsing mode. So,
OPTIONAL_LITERAL_NUMBER is reserved for OPTIONAL_CIV.
This commit is contained in:
Lei Zhang 2015-10-14 17:02:39 -04:00 committed by David Neto
parent 5d65ea726c
commit 6483bd7132
12 changed files with 170 additions and 107 deletions

View File

@ -102,8 +102,8 @@ include_directories(
set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
${CMAKE_CURRENT_SOURCE_DIR}/include/util/bitwisecast.h
${CMAKE_CURRENT_SOURCE_DIR}/source/binary.h
${CMAKE_CURRENT_SOURCE_DIR}/source/bitwisecast.h
${CMAKE_CURRENT_SOURCE_DIR}/source/diagnostic.h
${CMAKE_CURRENT_SOURCE_DIR}/source/ext_inst.h
${CMAKE_CURRENT_SOURCE_DIR}/source/instruction.h

View File

@ -154,7 +154,7 @@ typedef enum spv_operand_type_t {
SPV_OPERAND_TYPE_ID,
SPV_OPERAND_TYPE_TYPE_ID,
SPV_OPERAND_TYPE_RESULT_ID,
SPV_OPERAND_TYPE_LITERAL_NUMBER,
SPV_OPERAND_TYPE_LITERAL_INTEGER,
// A literal number that can (but is not required to) expand multiple words.
SPV_OPERAND_TYPE_MULTIWORD_LITERAL_NUMBER,
SPV_OPERAND_TYPE_LITERAL_STRING,
@ -200,8 +200,8 @@ typedef enum spv_operand_type_t {
// An optional image operands mask. A set bit in the mask may
// imply that more arguments are required.
SPV_OPERAND_TYPE_OPTIONAL_IMAGE,
// An optional literal number.
SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER,
// An optional literal integer.
SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER,
// An optional literal string.
SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING,
// An optional memory access qualifier mask, e.g. Volatile, Aligned,
@ -213,25 +213,28 @@ typedef enum spv_operand_type_t {
// In an instruction definition, this may only appear at the end of the
// operand types.
SPV_OPERAND_TYPE_VARIABLE_ID,
SPV_OPERAND_TYPE_VARIABLE_LITERAL_NUMBER,
// A sequence of zero or more pairs of (Literal number, Id)
SPV_OPERAND_TYPE_VARIABLE_LITERAL_NUMBER_ID,
// A sequence of zero or more pairs of (Id, Literal number)
SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_NUMBER,
SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER,
// A sequence of zero or more pairs of (Literal integer, Id)
SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID,
// A sequence of zero or more pairs of (Id, Literal integer)
SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER,
// A sequence of zero or more execution modes
SPV_OPERAND_TYPE_VARIABLE_EXECUTION_MODE,
// An Id that is second or later in an optional tuple of operands.
// This must be present if the first operand in the tuple is present.
SPV_OPERAND_TYPE_ID_IN_OPTIONAL_TUPLE,
// A Literal number that is second or later in an optional tuple of operands.
// A Literal integer that is second or later in an optional tuple of operands.
// This must be present if the first operand in the tuple is present.
SPV_OPERAND_TYPE_LITERAL_NUMBER_IN_OPTIONAL_TUPLE,
SPV_OPERAND_TYPE_LITERAL_INTEGER_IN_OPTIONAL_TUPLE,
// An optional context-independent value, or CIV. CIVs are tokens that we can
// assemble regardless of where they occur -- literals, IDs, immediate
// integers, etc.
SPV_OPERAND_TYPE_OPTIONAL_CIV,
// An optional literal number. This can expand to either a literal integer or
// a literal floating-point number.
SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER,
// This is a sentinel value, and does not represent an operand type.
// It should come last.

View File

@ -193,7 +193,7 @@ spv_result_t spvBinaryDecodeOperand(
stream.get() << ((color) ? clr::reset() : "");
position->index++;
} break;
case SPV_OPERAND_TYPE_LITERAL_NUMBER: {
case SPV_OPERAND_TYPE_LITERAL_INTEGER: {
// NOTE: Special case for extended instruction use
if (OpExtInst == opcode) {
spv_ext_inst_desc extInst;
@ -211,8 +211,8 @@ spv_result_t spvBinaryDecodeOperand(
}
} // Fall through for the general case.
case SPV_OPERAND_TYPE_MULTIWORD_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_LITERAL_NUMBER_IN_OPTIONAL_TUPLE: {
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
case SPV_OPERAND_TYPE_LITERAL_INTEGER_IN_OPTIONAL_TUPLE: {
// TODO: Need to support multiple word literals
stream.get() << (color ? clr::red() : "");
if (numWords > 2) {

View File

@ -106,11 +106,11 @@ spv_operand_type_t convertOperandClassToType(spv::Op opcode,
case OperandOptionalImage: return SPV_OPERAND_TYPE_OPTIONAL_IMAGE;
case OperandVariableIds: return SPV_OPERAND_TYPE_VARIABLE_ID;
// The spec only uses OptionalLiteral for an optional literal number.
case OperandOptionalLiteral: return SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER;
case OperandOptionalLiteral: return SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER;
case OperandOptionalLiteralString: return SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING;
// This is only used for sequences of literal numbers.
case OperandVariableLiterals: return SPV_OPERAND_TYPE_VARIABLE_LITERAL_NUMBER;
case OperandLiteralNumber: return SPV_OPERAND_TYPE_LITERAL_NUMBER;
case OperandVariableLiterals: return SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER;
case OperandLiteralNumber: return SPV_OPERAND_TYPE_LITERAL_INTEGER;
case OperandLiteralString: return SPV_OPERAND_TYPE_LITERAL_STRING;
case OperandSource: return SPV_OPERAND_TYPE_SOURCE_LANGUAGE;
case OperandExecutionModel: return SPV_OPERAND_TYPE_EXECUTION_MODEL;
@ -159,10 +159,10 @@ spv_operand_type_t convertOperandClassToType(spv::Op opcode,
case OperandCapability: return SPV_OPERAND_TYPE_CAPABILITY;
// Used by GroupMemberDecorate
case OperandVariableIdLiteral: return SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_NUMBER;
case OperandVariableIdLiteral: return SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER;
// Used by Switch
case OperandVariableLiteralId: return SPV_OPERAND_TYPE_VARIABLE_LITERAL_NUMBER_ID;
case OperandVariableLiteralId: return SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID;
// These exceptional cases shouldn't occur.
case OperandCount:

View File

@ -118,7 +118,7 @@ static const spv_operand_desc_t memoryModelEntries[] = {
// operand.
#define ExecMode1(mode, cap) \
#mode, ExecutionMode##mode, SPV_CAPABILITY_AS_MASK(Capability##cap), { \
SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE \
SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE \
}
static const spv_operand_desc_t executionModeEntries[] = {
{ExecMode1(Invocations, Geometry)},
@ -140,13 +140,13 @@ static const spv_operand_desc_t executionModeEntries[] = {
{"LocalSize",
ExecutionModeLocalSize,
0,
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_LITERAL_NUMBER,
SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER,
SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"LocalSizeHint",
ExecutionModeLocalSizeHint,
SPV_CAPABILITY_AS_MASK(CapabilityKernel),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_LITERAL_NUMBER,
SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER,
SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{ExecMode0(InputPoints, Geometry)},
{ExecMode0(InputLines, Geometry)},
{ExecMode0(InputLinesAdjacency, Geometry)},
@ -162,7 +162,7 @@ static const spv_operand_desc_t executionModeEntries[] = {
ExecutionModeOutputVertices,
SPV_CAPABILITY_AS_MASK(CapabilityGeometry) |
SPV_CAPABILITY_AS_MASK(CapabilityTessellation),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{ExecMode0(OutputPoints, Geometry)},
{ExecMode0(OutputLineStrip, Geometry)},
{ExecMode0(OutputTriangleStrip, Geometry)},
@ -542,7 +542,7 @@ static const spv_operand_desc_t decorationEntries[] = {
"SpecId",
DecorationSpecId,
SPV_CAPABILITY_AS_MASK(CapabilityShader),
{SPV_OPERAND_TYPE_LITERAL_NUMBER},
{SPV_OPERAND_TYPE_LITERAL_INTEGER},
},
{"Block",
DecorationBlock,
@ -563,11 +563,11 @@ static const spv_operand_desc_t decorationEntries[] = {
{"ArrayStride",
DecorationArrayStride,
SPV_CAPABILITY_AS_MASK(CapabilityShader),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"MatrixStride",
DecorationMatrixStride,
SPV_CAPABILITY_AS_MASK(CapabilityShader),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"GLSLShared",
DecorationGLSLShared,
SPV_CAPABILITY_AS_MASK(CapabilityShader),
@ -651,39 +651,39 @@ static const spv_operand_desc_t decorationEntries[] = {
{"Stream",
DecorationStream,
SPV_CAPABILITY_AS_MASK(CapabilityGeometry),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"Location",
DecorationLocation,
SPV_CAPABILITY_AS_MASK(CapabilityShader),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"Component",
DecorationComponent,
SPV_CAPABILITY_AS_MASK(CapabilityShader),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"Index",
DecorationIndex,
SPV_CAPABILITY_AS_MASK(CapabilityShader),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"Binding",
DecorationBinding,
SPV_CAPABILITY_AS_MASK(CapabilityShader),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"DescriptorSet",
DecorationDescriptorSet,
SPV_CAPABILITY_AS_MASK(CapabilityShader),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"Offset",
DecorationOffset,
0,
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"XfbBuffer",
DecorationXfbBuffer,
SPV_CAPABILITY_AS_MASK(CapabilityTransformFeedback),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"XfbStride",
DecorationXfbStride,
SPV_CAPABILITY_AS_MASK(CapabilityTransformFeedback),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
{"FuncParamAttr",
DecorationFuncParamAttr,
SPV_CAPABILITY_AS_MASK(CapabilityKernel),
@ -714,7 +714,7 @@ static const spv_operand_desc_t decorationEntries[] = {
{"Alignment",
DecorationAlignment,
SPV_CAPABILITY_AS_MASK(CapabilityKernel),
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}},
};
static const spv_operand_desc_t builtInEntries[] = {
@ -1012,7 +1012,7 @@ static const spv_operand_desc_t memoryAccessEntries[] = {
"Aligned",
MemoryAccessAlignedMask,
0,
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SPV_OPERAND_TYPE_NONE},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE},
},
{"Nontemporal",
MemoryAccessNontemporalMask,
@ -1314,7 +1314,7 @@ const char* spvOperandTypeStr(spv_operand_type_t type) {
return "ID";
case SPV_OPERAND_TYPE_RESULT_ID:
return "result ID";
case SPV_OPERAND_TYPE_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_LITERAL_INTEGER:
return "literal number";
case SPV_OPERAND_TYPE_MULTIWORD_LITERAL_NUMBER:
return "multiple word literal number";
@ -1418,6 +1418,7 @@ bool spvOperandIsOptional(spv_operand_type_t type) {
case SPV_OPERAND_TYPE_OPTIONAL_ID:
case SPV_OPERAND_TYPE_OPTIONAL_IMAGE:
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER:
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING:
case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
case SPV_OPERAND_TYPE_OPTIONAL_EXECUTION_MODE:
@ -1432,9 +1433,9 @@ bool spvOperandIsOptional(spv_operand_type_t type) {
bool spvOperandIsVariable(spv_operand_type_t type) {
switch (type) {
case SPV_OPERAND_TYPE_VARIABLE_ID:
case SPV_OPERAND_TYPE_VARIABLE_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_VARIABLE_LITERAL_NUMBER_ID:
case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER:
case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER:
case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID:
case SPV_OPERAND_TYPE_VARIABLE_EXECUTION_MODE:
return true;
default:
@ -1449,22 +1450,22 @@ bool spvExpandOperandSequenceOnce(spv_operand_type_t type,
case SPV_OPERAND_TYPE_VARIABLE_ID:
pattern->insert(pattern->begin(), {SPV_OPERAND_TYPE_OPTIONAL_ID, type});
return true;
case SPV_OPERAND_TYPE_VARIABLE_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER:
pattern->insert(pattern->begin(),
{SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER, type});
{SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER, type});
return true;
case SPV_OPERAND_TYPE_VARIABLE_LITERAL_NUMBER_ID:
case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID:
// Represents Zero or more (Literal number, Id) pairs.
pattern->insert(pattern->begin(),
{SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER,
{SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER,
SPV_OPERAND_TYPE_ID_IN_OPTIONAL_TUPLE, type});
return true;
case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER:
// Represents Zero or more (Id, Literal number) pairs.
pattern->insert(
pattern->begin(),
{SPV_OPERAND_TYPE_OPTIONAL_ID,
SPV_OPERAND_TYPE_LITERAL_NUMBER_IN_OPTIONAL_TUPLE, type});
SPV_OPERAND_TYPE_LITERAL_INTEGER_IN_OPTIONAL_TUPLE, type});
return true;
case SPV_OPERAND_TYPE_VARIABLE_EXECUTION_MODE:
pattern->insert(pattern->begin(),

View File

@ -39,7 +39,6 @@
#include <vector>
#include "binary.h"
#include "bitwisecast.h"
#include "diagnostic.h"
#include "ext_inst.h"
#include "instruction.h"
@ -47,6 +46,7 @@
#include "opcode.h"
#include "operand.h"
#include "text_handler.h"
#include "util/bitwisecast.h"
bool spvIsValidIDCharacter(const char value) {
return value == '_' || 0 != ::isalnum(value);
@ -111,7 +111,7 @@ spv_result_t spvTextToLiteral(const char* textValue, spv_literal_t* pLiteral) {
return SPV_FAILED_MATCH;
bool escaping = false;
size_t write_index = 0;
for(const char* val = textValue + 1; val != textValue + len - 1; ++val) {
for (const char* val = textValue + 1; val != textValue + len - 1; ++val) {
if ((*val == '\\') && (!escaping)) {
escaping = true;
} else {
@ -234,7 +234,7 @@ spv_result_t spvTextEncodeOperand(const libspirv::AssemblyGrammar& grammar,
if (type == SPV_OPERAND_TYPE_TYPE_ID) pInst->resultTypeId = id;
spvInstructionAddWord(pInst, id);
} break;
case SPV_OPERAND_TYPE_LITERAL_NUMBER: {
case SPV_OPERAND_TYPE_LITERAL_INTEGER: {
// NOTE: Special case for extension instruction lookup
if (OpExtInst == pInst->opcode) {
spv_ext_inst_desc extInst;
@ -251,35 +251,41 @@ spv_result_t spvTextEncodeOperand(const libspirv::AssemblyGrammar& grammar,
}
} // Fall through for the general case.
case SPV_OPERAND_TYPE_MULTIWORD_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_LITERAL_NUMBER_IN_OPTIONAL_TUPLE:
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER: {
case SPV_OPERAND_TYPE_LITERAL_INTEGER_IN_OPTIONAL_TUPLE:
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER: {
libspirv::IdType expected_type = libspirv::kUnknownType;
// The encoding for OpConstant, OpSpecConstant and OpSwitch all
// depend on either their own result-id or the result-id of
// one of their parameters.
if (OpConstant == pInst->opcode || OpSpecConstant == pInst->opcode) {
// Special cases for encoding possibly non-32-bit literals here.
expected_type =
context->getTypeOfTypeGeneratingValue(pInst->resultTypeId);
if (!libspirv::isScalarFloating(expected_type) &&
!libspirv::isScalarIntegral(expected_type)) {
spv_opcode_desc d;
const char* opcode_name = "opcode";
if (SPV_SUCCESS == grammar.lookupOpcode(pInst->opcode, &d)) {
opcode_name = d->name;
if (type != SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER) {
// From now, it's safe to assume that the current operand is an unsigned
// integer, apart from the special cases handled below.
expected_type = {32, false, libspirv::IdTypeClass::kScalarIntegerType};
// The encoding for OpConstant, OpSpecConstant and OpSwitch all
// depend on either their own result-id or the result-id of
// one of their parameters.
if (OpConstant == pInst->opcode || OpSpecConstant == pInst->opcode) {
// Special cases for encoding possibly non-32-bit literals here.
expected_type =
context->getTypeOfTypeGeneratingValue(pInst->resultTypeId);
if (!libspirv::isScalarFloating(expected_type) &&
!libspirv::isScalarIntegral(expected_type)) {
spv_opcode_desc d;
const char* opcode_name = "opcode";
if (SPV_SUCCESS == grammar.lookupOpcode(pInst->opcode, &d)) {
opcode_name = d->name;
}
return context->diagnostic()
<< "Type for " << opcode_name
<< " must be a scalar floating point or integer type";
}
} else if (pInst->opcode == OpSwitch) {
// We need to know the type of the selector.
expected_type = context->getTypeOfValueInstruction(pInst->words[1]);
if (!libspirv::isScalarIntegral(expected_type)) {
context->diagnostic()
<< "The selector operand for OpSwitch must be the result"
" of an instruction that generates an integer scalar";
return SPV_ERROR_INVALID_TEXT;
}
return context->diagnostic()
<< "Type for " << opcode_name
<< " must be a scalar floating point or integer type";
}
} else if (pInst->opcode == OpSwitch) {
// We need to know the type of the selector.
expected_type = context->getTypeOfValueInstruction(pInst->words[1]);
if (!libspirv::isScalarIntegral(expected_type)) {
context->diagnostic()
<< "The selector operand for OpSwitch must be the result"
" of an instruction that generates an integer scalar";
return SPV_ERROR_INVALID_TEXT;
}
}
@ -479,8 +485,7 @@ spv_result_t spvTextEncodeOpcode(const libspirv::AssemblyGrammar& grammar,
if (context->advance())
return context->diagnostic() << "Expected opcode, found end of stream.";
error = context->getWord(opcodeName, &nextPosition);
if (error)
return context->diagnostic(error) << "Internal Error";
if (error) return context->diagnostic(error) << "Internal Error";
if (!context->startsWithOp()) {
return context->diagnostic() << "Invalid Opcode prefix '" << opcodeName
<< "'.";
@ -654,7 +659,8 @@ spv_result_t spvTextToBinaryInternal(const libspirv::AssemblyGrammar& grammar,
if (!data) return SPV_ERROR_OUT_OF_MEMORY;
uint64_t currentIndex = SPV_INDEX_INSTRUCTION;
for (auto& inst : instructions) {
memcpy(data + currentIndex, inst.words.data(), sizeof(uint32_t) * inst.words.size());
memcpy(data + currentIndex, inst.words.data(),
sizeof(uint32_t) * inst.words.size());
currentIndex += inst.words.size();
}

View File

@ -33,11 +33,11 @@
#include <tuple>
#include "binary.h"
#include "bitwisecast.h"
#include "ext_inst.h"
#include "instruction.h"
#include "opcode.h"
#include "text.h"
#include "util/bitwisecast.h"
namespace {

View File

@ -81,7 +81,7 @@ spv_result_t spvValidateOperandValue(const spv_operand_type_t type,
// NOTE: ID's are validated in SPV_VALIDATION_LEVEL_1, this is
// SPV_VALIDATION_LEVEL_0
} break;
case SPV_OPERAND_TYPE_LITERAL_NUMBER: {
case SPV_OPERAND_TYPE_LITERAL_INTEGER: {
// NOTE: Implicitly valid as they are encoded as 32 bit value
} break;
case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
@ -168,7 +168,7 @@ spv_result_t spvValidateBasic(const spv_instruction_t *pInsts,
words + index, wordCount - index, position, pDiagnostic));
// NOTE: String literals are always at the end of Opcodes
break;
} else if (SPV_OPERAND_TYPE_LITERAL_NUMBER == type) {
} else if (SPV_OPERAND_TYPE_LITERAL_INTEGER == type) {
spvCheckReturn(spvValidateOperandsLiteral(
words + index, wordCount - index, 2, position, pDiagnostic));
} else {

View File

@ -31,11 +31,14 @@
#include <gmock/gmock.h>
#include "TestFixture.h"
#include "util/bitwisecast.h"
namespace {
using spvtest::Concatenate;
using spvtest::MakeInstruction;
using spvtest::TextToBinaryTest;
using spvutils::BitwiseCast;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::HasSubstr;
@ -69,7 +72,7 @@ using ImmediateIntTest = TextToBinaryTest;
TEST_F(ImmediateIntTest, AnyWordInSimpleStatement) {
EXPECT_THAT(CompiledInstructions("!0x00040018 %a %b %123", kCAF),
Eq(MakeInstruction(spv::OpTypeMatrix, {1, 2,3 })));
Eq(MakeInstruction(spv::OpTypeMatrix, {1, 2, 3})));
EXPECT_THAT(CompiledInstructions("OpTypeMatrix !1 %b %123", kCAF),
Eq(MakeInstruction(spv::OpTypeMatrix, {1, 1, 2})));
EXPECT_THAT(CompiledInstructions("OpTypeMatrix %1 !2 %123", kCAF),
@ -117,17 +120,30 @@ TEST_F(ImmediateIntTest, IntegerFollowingImmediate) {
EXPECT_EQ(original, CompiledInstructions("!0x00040015 1 8 1", kCAF));
EXPECT_EQ(original, CompiledInstructions("OpTypeInt !1 8 1", kCAF));
// 64-bit integer literal.
EXPECT_EQ(CompiledInstructions("OpTypeInt %i64 64 0\n"
"OpConstant %i64 %2 5000000000", kCAF),
// With !<integer>, we can (and can only) accept 32-bit number literals,
// even when we declare the return type is 64-bit.
EXPECT_EQ(Concatenate({
MakeInstruction(OpTypeInt, {1, 64, 0}),
MakeInstruction(OpConstant, {1, 2, 4294967295}),
}),
CompiledInstructions("OpTypeInt %i64 64 0\n"
"OpConstant %i64 !2 5000000000", kCAF));
"OpConstant %i64 !2 4294967295",
kCAF));
// 64-bit integer literal.
EXPECT_EQ("Invalid word following !<integer>: 5000000000",
CompileFailure("OpConstant !1 %2 5000000000", kCAF));
EXPECT_EQ("Invalid word following !<integer>: 5000000000",
CompileFailure("OpTypeInt %i64 64 0\n"
"OpConstant %i64 !2 5000000000",
kCAF));
// Negative integer.
EXPECT_EQ(CompiledInstructions("OpTypeInt %i64 32 1\n"
"OpConstant %i64 %2 -123", kCAF),
"OpConstant %i64 %2 -123",
kCAF),
CompiledInstructions("OpTypeInt %i64 32 1\n"
"OpConstant %i64 !2 -123", kCAF));
"OpConstant %i64 !2 -123",
kCAF));
// TODO(deki): uncomment assertions below and make them pass.
// Hex value(s).
@ -140,10 +156,28 @@ TEST_F(ImmediateIntTest, IntegerFollowingImmediate) {
// Literal floats after !<integer> are handled correctly.
TEST_F(ImmediateIntTest, FloatFollowingImmediate) {
EXPECT_EQ(CompiledInstructions("OpTypeMatrix %10 %2 0.123", kCAF),
CompiledInstructions("OpTypeMatrix %10 !2 0.123", kCAF));
EXPECT_EQ(CompiledInstructions("OpTypeMatrix %10 %2 -0.5", kCAF),
CompiledInstructions("OpTypeMatrix %10 !2 -0.5", kCAF));
EXPECT_EQ(
CompiledInstructions("OpTypeFloat %1 32\nOpConstant %1 %2 0.123", kCAF),
CompiledInstructions("OpTypeFloat %1 32\nOpConstant %1 !2 0.123", kCAF));
EXPECT_EQ(
CompiledInstructions("OpTypeFloat %1 32\nOpConstant %1 %2 -0.5", kCAF),
CompiledInstructions("OpTypeFloat %1 32\nOpConstant %1 !2 -0.5", kCAF));
EXPECT_EQ(
CompiledInstructions("OpTypeFloat %1 32\nOpConstant %1 %2 0.123", kCAF),
CompiledInstructions("OpTypeFloat %1 32\n!0x0004002b %1 %2 0.123", kCAF));
EXPECT_EQ(
CompiledInstructions("OpTypeFloat %1 32\nOpConstant %1 %2 -0.5", kCAF),
CompiledInstructions("OpTypeFloat %1 32\n!0x0004002b %1 %2 -0.5", kCAF));
EXPECT_EQ(
Concatenate({
MakeInstruction(OpTypeInt, {1, 64, 0}),
MakeInstruction(OpConstant, {1, 2, 0xb, 0xa}),
MakeInstruction(OpSwitch, {2, 1234, BitwiseCast<uint32_t>(2.5f), 3}),
}),
CompiledInstructions("%i64 = OpTypeInt 64 0\n"
"%big = OpConstant %i64 0xa0000000b\n"
"OpSwitch %big !1234 2.5 %target\n"));
}
// Literal strings after !<integer> are handled correctly.
@ -272,12 +306,10 @@ TEST_F(ImmediateIntTest, ForbiddenOperands) {
}
TEST_F(ImmediateIntTest, NotInteger) {
EXPECT_THAT(CompileFailure("!abc"),
StrEq("Invalid immediate integer: !abc"));
EXPECT_THAT(CompileFailure("!abc"), StrEq("Invalid immediate integer: !abc"));
EXPECT_THAT(CompileFailure("!12.3"),
StrEq("Invalid immediate integer: !12.3"));
EXPECT_THAT(CompileFailure("!12K"),
StrEq("Invalid immediate integer: !12K"));
EXPECT_THAT(CompileFailure("!12K"), StrEq("Invalid immediate integer: !12K"));
}
} // anonymous namespace

View File

@ -58,7 +58,7 @@ TEST(OperandPattern, PushFrontsAreOnTheLeft) {
}
TEST(OperandPattern, PopFrontsAreOnTheLeft) {
spv_operand_pattern_t pattern{SPV_OPERAND_TYPE_LITERAL_NUMBER,
spv_operand_pattern_t pattern{SPV_OPERAND_TYPE_LITERAL_INTEGER,
SPV_OPERAND_TYPE_ID};
pattern.pop_front();
@ -112,12 +112,12 @@ INSTANTIATE_TEST_CASE_P(
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
spv::MemoryAccessAlignedMask,
{SUFFIX1},
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SUFFIX1}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SUFFIX1}},
// Volatile with Aligned still has just one literal number operand.
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
spv::MemoryAccessVolatileMask | spv::MemoryAccessAlignedMask,
{SUFFIX1},
{SPV_OPERAND_TYPE_LITERAL_NUMBER, SUFFIX1}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, SUFFIX1}},
}));
#undef SUFFIX0
#undef SUFFIX1
@ -176,7 +176,7 @@ TEST(AlternatePatternFollowingImmediate, Empty) {
TEST(AlternatePatternFollowingImmediate, SingleElement) {
// Spot-check a random selection of types.
EXPECT_THAT(spvAlternatePatternFollowingImmediate(
{SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_NUMBER}),
{SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER}),
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
EXPECT_THAT(
spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_CAPABILITY}),
@ -185,7 +185,7 @@ TEST(AlternatePatternFollowingImmediate, SingleElement) {
spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_LOOP_CONTROL}),
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
EXPECT_THAT(spvAlternatePatternFollowingImmediate(
{SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER}),
{SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER}),
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
EXPECT_THAT(spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_ID}),
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
@ -204,9 +204,9 @@ TEST(AlternatePatternFollowingImmediate, SingleResultId) {
TEST(AlternatePatternFollowingImmediate, MultipleNonResultIds) {
EXPECT_THAT(
spvAlternatePatternFollowingImmediate(
{SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_NUMBER,
{SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER,
SPV_OPERAND_TYPE_CAPABILITY, SPV_OPERAND_TYPE_LOOP_CONTROL,
SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER, SPV_OPERAND_TYPE_ID,
SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID,
SPV_OPERAND_TYPE_VARIABLE_EXECUTION_MODE}),
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
}

View File

@ -48,6 +48,27 @@ TEST_F(TextToBinaryTest, LiteralNumberInPlaceOfLiteralString) {
CompileFailure("OpSourceExtension 1000"));
}
TEST_F(TextToBinaryTest, LiteralFloatInPlaceOfLiteralInteger) {
EXPECT_EQ("Invalid unsigned integer literal: 10.5",
CompileFailure("OpSource GLSL 10.5"));
EXPECT_EQ("Invalid unsigned integer literal: 0.2",
CompileFailure(R"(OpMemberName %type 0.2 "member0.2")"));
EXPECT_EQ("Invalid unsigned integer literal: 32.42",
CompileFailure("%int = OpTypeInt 32.42 0"));
EXPECT_EQ("Invalid unsigned integer literal: 4.5",
CompileFailure("%mat = OpTypeMatrix %vec 4.5"));
EXPECT_EQ("Invalid unsigned integer literal: 1.5",
CompileFailure("OpExecutionMode %main LocalSize 1.5 1.6 1.7"));
EXPECT_EQ("Invalid unsigned integer literal: 0.123",
CompileFailure("%i32 = OpTypeInt 32 1\n"
"%c = OpConstant %i32 0.123"));
}
TEST_F(TextToBinaryTest, LiteralStringASCIILong) {
// SPIR-V allows strings up to 65535 characters.
// Test the simple case of UTF-8 code points corresponding