Remove dependency on SPIR-V headers in libspirv.h.

For fulfilling this purpose, the |opcode| field in the
|spv_parsed_instruction_t| struct is changed to of type uint16_t.

Also add functions to query the information of a given SPIR-V
target environment.
This commit is contained in:
Lei Zhang 2016-03-31 17:26:31 -04:00
parent d03c0a1153
commit 6fa3f8aad9
31 changed files with 156 additions and 132 deletions

View File

@ -159,9 +159,3 @@ add_subdirectory(test)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/spirv-tools/libspirv.h
DESTINATION include/spirv-tools/)
# The installation is broken without these header files from the SPIR-V Registry.
# The libspirv.h header includes them.
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/spirv/spirv.h
${CMAKE_CURRENT_SOURCE_DIR}/include/spirv/GLSL.std.450.h
${CMAKE_CURRENT_SOURCE_DIR}/include/spirv/OpenCL.std.h
DESTINATION include/spirv/)

View File

@ -27,10 +27,6 @@
#ifndef SPIRV_TOOLS_LIBSPIRV_H_
#define SPIRV_TOOLS_LIBSPIRV_H_
#include "spirv/GLSL.std.450.h"
#include "spirv/OpenCL.std.h"
#include "spirv/spirv.h"
#ifdef __cplusplus
extern "C" {
#else
@ -40,18 +36,8 @@ extern "C" {
#include <stddef.h>
#include <stdint.h>
// Versions
// This library is based on SPIR-V 1.0 Rev2
// TODO(dneto): Use the values from the SPIR-V header, when it's updated for
// SPIR-V 1.0 public release.
#define SPV_SPIRV_VERSION_MAJOR (SPV_VERSION >> 16)
#define SPV_SPIRV_VERSION_MINOR (SPV_VERSION & 0xffff)
#define SPV_SPIRV_VERSION_REVISION (SPV_REVISION)
// Helpers
#define spvIsInBitfield(value, bitfield) ((value) == ((value)&bitfield))
#define SPV_BIT(shift) (1 << (shift))
#define SPV_FORCE_16_BIT_ENUM(name) _##name = 0x7fff
@ -287,7 +273,7 @@ typedef struct spv_parsed_instruction_t {
const uint32_t* words;
// The number of words in this instruction.
uint16_t num_words;
SpvOp opcode;
uint16_t opcode;
// The extended instruction type, if opcode is OpExtInst. Otherwise
// this is the "none" value.
spv_ext_inst_type_t ext_inst_type;
@ -353,6 +339,9 @@ typedef enum {
SPV_ENV_VULKAN_1_0_7 // Vulkan 1.0 revision 7.
} spv_target_env;
// Returns a string describing the given SPIR-V target environment.
const char* spvTargetEnvDescription(spv_target_env env);
// Creates a context object. Returns null if env is invalid.
spv_context spvContextCreate(spv_target_env env);

View File

@ -29,6 +29,7 @@ set(SPIRV_SOURCES
${spirv-tools_SOURCE_DIR}/include/spirv/spirv.h
${spirv-tools_SOURCE_DIR}/include/spirv/GLSL.std.450.h
${spirv-tools_SOURCE_DIR}/include/spirv/OpenCL.std.h
${CMAKE_CURRENT_SOURCE_DIR}/util/bitutils.h
${CMAKE_CURRENT_SOURCE_DIR}/util/hex_float.h
${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.h
@ -46,16 +47,18 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/text.h
${CMAKE_CURRENT_SOURCE_DIR}/text_handler.h
${CMAKE_CURRENT_SOURCE_DIR}/validate.h
${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.cpp
${CMAKE_CURRENT_SOURCE_DIR}/binary.cpp
${CMAKE_CURRENT_SOURCE_DIR}/disassemble.cpp
${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.cpp
${CMAKE_CURRENT_SOURCE_DIR}/disassemble.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.cpp
${CMAKE_CURRENT_SOURCE_DIR}/instruction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/opcode.cpp
${CMAKE_CURRENT_SOURCE_DIR}/operand.cpp
${CMAKE_CURRENT_SOURCE_DIR}/print.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_endian.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.cpp
${CMAKE_CURRENT_SOURCE_DIR}/table.cpp
${CMAKE_CURRENT_SOURCE_DIR}/text.cpp
${CMAKE_CURRENT_SOURCE_DIR}/text_handler.cpp

View File

@ -29,6 +29,7 @@
#include "operand.h"
#include "spirv-tools/libspirv.h"
#include "spirv/spirv.h"
#include "table.h"
namespace libspirv {
@ -38,13 +39,17 @@ namespace libspirv {
class AssemblyGrammar {
public:
explicit AssemblyGrammar(const spv_const_context context)
: operandTable_(context->operand_table),
: target_env_(context->target_env),
operandTable_(context->operand_table),
opcodeTable_(context->opcode_table),
extInstTable_(context->ext_inst_table) {}
// Returns true if the internal tables have been initialized with valid data.
bool isValid() const;
// Returns the SPIR-V target environment.
spv_target_env target_env() const { return target_env_; }
// Fills in the desc parameter with the information about the opcode
// of the given name. Returns SPV_SUCCESS if the opcode was found, and
// SPV_ERROR_INVALID_LOOKUP if the opcode does not exist.
@ -115,6 +120,7 @@ class AssemblyGrammar {
spv_operand_pattern_t* pattern) const;
private:
const spv_target_env target_env_;
const spv_operand_table operandTable_;
const spv_opcode_table opcodeTable_;
const spv_ext_inst_table extInstTable_;

View File

@ -300,8 +300,8 @@ spv_result_t Parser::parseInstruction() {
<< inst_word_count;
}
spv_opcode_desc opcode_desc;
if (grammar_.lookupOpcode(inst.opcode, &opcode_desc))
return diagnostic() << "Invalid opcode: " << int(inst.opcode);
if (grammar_.lookupOpcode(static_cast<SpvOp>(inst.opcode), &opcode_desc))
return diagnostic() << "Invalid opcode: " << inst.opcode;
// Advance past the opcode word. But remember the of the start
// of the instruction.
@ -397,6 +397,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
std::vector<uint32_t>* words,
std::vector<spv_parsed_operand_t>* operands,
spv_operand_pattern_t* expected_operands) {
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
// We'll fill in this result as we go along.
spv_parsed_operand_t parsed_operand;
parsed_operand.offset = uint16_t(_.word_index - inst_offset);
@ -414,7 +415,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
parsed_operand.number_bit_width = 0;
if (_.word_index >= _.num_words)
return exhaustedInputDiagnostic(inst_offset, inst->opcode, type);
return exhaustedInputDiagnostic(inst_offset, opcode, type);
const uint32_t word = peek();
@ -442,9 +443,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
// A regular value maps to its type. Some instructions (e.g. OpLabel)
// have no type Id, and will map to 0. The result Id for a
// type-generating instruction (e.g. OpTypeInt) maps to itself.
_.id_to_type_id[inst->result_id] = spvOpcodeGeneratesType(inst->opcode)
? inst->result_id
: inst->type_id;
_.id_to_type_id[inst->result_id] =
spvOpcodeGeneratesType(opcode) ? inst->result_id : inst->type_id;
break;
case SPV_OPERAND_TYPE_ID:
@ -452,7 +452,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
if (!word) return diagnostic(SPV_ERROR_INVALID_ID) << "Id is 0";
parsed_operand.type = SPV_OPERAND_TYPE_ID;
if (inst->opcode == SpvOpExtInst && parsed_operand.offset == 3) {
if (opcode == SpvOpExtInst && parsed_operand.offset == 3) {
// The current word is the extended instruction set Id.
// Set the extended instruction set type for the current instruction.
auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word);
@ -473,7 +473,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
break;
case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
assert(SpvOpExtInst == inst->opcode);
assert(SpvOpExtInst == opcode);
assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE);
spv_ext_inst_desc ext_inst;
if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst))
@ -482,7 +482,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
} break;
case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
assert(SpvOpSpecConstantOp == inst->opcode);
assert(SpvOpSpecConstantOp == opcode);
if (grammar_.lookupSpecConstantOpcode(SpvOp(word))) {
return diagnostic() << "Invalid " << spvOperandTypeStr(type) << ": "
<< word;
@ -514,7 +514,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
if (inst->opcode == SpvOpSwitch) {
if (opcode == SpvOpSwitch) {
// The literal operands have the same type as the value
// referenced by the selector Id.
const uint32_t selector_id = peekAt(inst_offset + 1);
@ -540,8 +540,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
<< " is not a scalar integer";
}
} else {
assert(inst->opcode == SpvOpConstant ||
inst->opcode == SpvOpSpecConstant);
assert(opcode == SpvOpConstant || opcode == SpvOpSpecConstant);
// The literal number type is determined by the type Id for the
// constant.
assert(inst->type_id);
@ -565,7 +564,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
// If there was no terminating null byte, then that's an end-of-input
// error.
if (string_num_content_bytes == remaining_input_bytes)
return exhaustedInputDiagnostic(inst_offset, inst->opcode, type);
return exhaustedInputDiagnostic(inst_offset, opcode, type);
// Account for null in the word length, so add 1 for null, then add 3 to
// make sure we round up. The following is equivalent to:
// (string_num_content_bytes + 1 + 3) / 4
@ -582,7 +581,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
parsed_operand.num_words = uint16_t(string_num_words);
parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING;
if (SpvOpExtInstImport == inst->opcode) {
if (SpvOpExtInstImport == opcode) {
// Record the extended instruction type for the ID for this import.
// There is only one string literal argument to OpExtInstImport,
// so it's sufficient to guard this just on the opcode.
@ -696,7 +695,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
// handled earlier.) For example, this error can occur for a multi-word
// argument to OpConstant, or a multi-word case literal operand for OpSwitch.
if (_.num_words < index_after_operand)
return exhaustedInputDiagnostic(inst_offset, inst->opcode, type);
return exhaustedInputDiagnostic(inst_offset, opcode, type);
if (_.requires_endian_conversion) {
// Copy instruction words. Translate to native endianness as needed.
@ -742,13 +741,14 @@ spv_result_t Parser::setNumericTypeInfoForType(
void Parser::recordNumberType(size_t inst_offset,
const spv_parsed_instruction_t* inst) {
if (spvOpcodeGeneratesType(inst->opcode)) {
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
if (spvOpcodeGeneratesType(opcode)) {
NumberType info = {SPV_NUMBER_NONE, 0};
if (SpvOpTypeInt == inst->opcode) {
if (SpvOpTypeInt == opcode) {
const bool is_signed = peekAt(inst_offset + 3) != 0;
info.type = is_signed ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT;
info.bit_width = peekAt(inst_offset + 2);
} else if (SpvOpTypeFloat == inst->opcode) {
} else if (SpvOpTypeFloat == opcode) {
info.type = SPV_NUMBER_FLOATING;
info.bit_width = peekAt(inst_offset + 2);
}

View File

@ -182,7 +182,7 @@ spv_result_t Disassembler::HandleInstruction(
stream_ << std::string(indent_, ' ');
}
stream_ << "Op" << spvOpcodeString(inst.opcode);
stream_ << "Op" << spvOpcodeString(static_cast<SpvOp>(inst.opcode));
for (uint16_t i = 0; i < inst.num_operands; i++) {
const spv_operand_type_t type = inst.operands[i].type;

View File

@ -28,16 +28,18 @@
#include <string.h>
#include "spirv/GLSL.std.450.h"
#include "spirv/OpenCL.std.h"
#include "spirv_definition.h"
/// Generate a spv_ext_inst_desc_t literal for a GLSL std450 extended
/// instruction with one/two/three <id> parameter(s).
#define GLSL450Inst1(name) \
#name, GLSLstd450::GLSLstd450##name, 0, { SPV_OPERAND_TYPE_ID }
#define GLSL450Inst1Cap(name, cap) \
#name, GLSLstd450::GLSLstd450##name, \
SPV_CAPABILITY_AS_MASK(SpvCapability##cap), { \
SPV_OPERAND_TYPE_ID \
#define GLSL450Inst1Cap(name, cap) \
#name, GLSLstd450::GLSLstd450##name, \
SPV_CAPABILITY_AS_MASK(SpvCapability##cap), { \
SPV_OPERAND_TYPE_ID \
}
#define GLSL450Inst2(name) \
#name, GLSLstd450::GLSLstd450##name, 0, { \
@ -138,9 +140,7 @@ static const spv_ext_inst_desc_t glslStd450Entries[] = {
};
static const spv_ext_inst_desc_t openclEntries[] = {
#define ExtInst(Name, Opcode, OperandList) \
{ #Name, Opcode, 0, OperandList } \
,
#define ExtInst(Name, Opcode, OperandList) {#Name, Opcode, 0, OperandList},
#define EmptyList \
{}
#define List(...) \

View File

@ -82,12 +82,13 @@ uint32_t spvOpcodeMake(uint16_t wordCount, SpvOp opcode) {
return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16);
}
void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount, SpvOp* pOpcode) {
void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount,
uint16_t* pOpcode) {
if (pWordCount) {
*pWordCount = (uint16_t)((0xffff0000 & word) >> 16);
}
if (pOpcode) {
*pOpcode = (SpvOp)(0x0000ffff & word);
*pOpcode = 0x0000ffff & word;
}
}
@ -162,10 +163,10 @@ void spvInstructionCopy(const uint32_t* words, const SpvOp opcode,
pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
if (!wordIndex) {
uint16_t thisWordCount;
SpvOp thisOpcode;
uint16_t thisOpcode;
spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
assert(opcode == thisOpcode && wordCount == thisWordCount &&
"Endianness failed!");
assert(opcode == static_cast<SpvOp>(thisOpcode) &&
wordCount == thisWordCount && "Endianness failed!");
}
}
}

View File

@ -29,6 +29,7 @@
#include "instruction.h"
#include "spirv-tools/libspirv.h"
#include "spirv/spirv.h"
#include "table.h"
// Returns the name of a registered SPIR-V generator as a null-terminated
@ -43,7 +44,8 @@ const char* spvGeneratorStr(uint32_t generator);
uint32_t spvOpcodeMake(uint16_t word_count, SpvOp opcode);
// Splits word into into two constituent parts: word_count and opcode.
void spvOpcodeSplit(const uint32_t word, uint16_t* word_count, SpvOp* opcode);
void spvOpcodeSplit(const uint32_t word, uint16_t* word_count,
uint16_t* opcode);
// Finds the named opcode in the given opcode table. On success, returns
// SPV_SUCCESS and writes a handle of the table entry into *entry.

View File

@ -28,6 +28,7 @@
#define LIBSPIRV_SPIRV_CONSTANT_H_
#include "spirv-tools/libspirv.h"
#include "spirv/spirv.h"
// Version number macros.
@ -40,6 +41,9 @@
// Returns the minor version extracted from a version header word.
#define SPV_SPIRV_VERSION_MINOR_PART(WORD) ((uint32_t(WORD) >> 8) & 0xff)
// Returns the version number for the given SPIR-V target environment.
uint32_t spvVersionForTargetEnv(spv_target_env env);
// Header indices
#define SPV_INDEX_MAGIC_NUMBER 0u

View File

@ -31,6 +31,8 @@
#include "spirv-tools/libspirv.h"
#define spvIsInBitfield(value, bitfield) ((value) == ((value)&bitfield))
// A bit mask representing a set of capabilities.
// Currently there are 57 distinct capabilities, so 64 bits
// should be enough.

View File

@ -1,4 +1,4 @@
// Copyright 2016 Google Inc. All Rights Reserved.
// Copyright (c) 2015-2016 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
@ -24,16 +24,38 @@
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include "gmock/gmock.h"
#include <assert.h>
#include "UnitSPIRV.h"
#include "spirv-tools/libspirv.h"
#include "spirv_constant.h"
namespace {
TEST(LibspirvMacros, Version) {
EXPECT_EQ(1, SPV_SPIRV_VERSION_MAJOR);
EXPECT_EQ(0, SPV_SPIRV_VERSION_MINOR);
EXPECT_EQ(3, SPV_SPIRV_VERSION_REVISION);
const char* spvTargetEnvDescription(spv_target_env env) {
switch (env) {
case SPV_ENV_UNIVERSAL_1_0:
return "SPIR-V 1.0";
case SPV_ENV_UNIVERSAL_1_0_4:
return "SPIR-V 1.0 rev 4";
case SPV_ENV_VULKAN_1_0:
return "SPIR-V 1.0 (under Vulkan 1.0 semantics)";
case SPV_ENV_VULKAN_1_0_7:
return "SPIR-V 1.0 (under Vulkan 1.0.7 semantics)";
default:
break;
}
assert(0 && "Unhandled SPIR-V target environment");
return "";
}
} // anonymous namespace
uint32_t spvVersionForTargetEnv(spv_target_env env) {
switch (env) {
case SPV_ENV_UNIVERSAL_1_0:
case SPV_ENV_UNIVERSAL_1_0_4:
case SPV_ENV_VULKAN_1_0:
case SPV_ENV_VULKAN_1_0_7:
return SPV_SPIRV_VERSION_WORD(1, 0);
default:
break;
}
assert(0 && "Unhandled SPIR-V target environment");
return SPV_SPIRV_VERSION_WORD(0, 0);
}

View File

@ -47,7 +47,7 @@ spv_context spvContextCreate(spv_target_env env) {
spvOperandTableGet(&operand_table);
spvExtInstTableGet(&ext_inst_table);
return new spv_context_t{opcode_table, operand_table, ext_inst_table};
return new spv_context_t{env, opcode_table, operand_table, ext_inst_table};
}
void spvContextDestroy(spv_context context) { delete context; }

View File

@ -28,6 +28,7 @@
#define LIBSPIRV_TABLE_H_
#include "spirv-tools/libspirv.h"
#include "spirv/spirv.h"
#include "spirv_definition.h"
typedef struct spv_opcode_desc_t {
@ -96,6 +97,7 @@ typedef const spv_operand_table_t* spv_operand_table;
typedef const spv_ext_inst_table_t* spv_ext_inst_table;
struct spv_context_t {
const spv_target_env target_env;
const spv_opcode_table opcode_table;
const spv_operand_table operand_table;
const spv_ext_inst_table ext_inst_table;

View File

@ -653,22 +653,18 @@ spv_result_t spvTextEncodeOpcode(const libspirv::AssemblyGrammar& grammar,
enum { kAssemblerVersion = 0 };
/// @brief Populate a binary stream's words with this generator's header.
///
/// @param[in,out] words the array of words
/// @param[in] bound the upper ID bound
///
/// @return result code
spv_result_t SetHeader(uint32_t* words, const uint32_t bound) {
if (!words) return SPV_ERROR_INVALID_BINARY;
// Populates a binary stream's |header|. The target environment is specified via
// |env| and Id bound is via |bound|.
spv_result_t SetHeader(spv_target_env env, const uint32_t bound,
uint32_t* header) {
if (!header) return SPV_ERROR_INVALID_BINARY;
words[SPV_INDEX_MAGIC_NUMBER] = SpvMagicNumber;
words[SPV_INDEX_VERSION_NUMBER] =
SPV_SPIRV_VERSION_WORD(SPV_SPIRV_VERSION_MAJOR, SPV_SPIRV_VERSION_MINOR);
words[SPV_INDEX_GENERATOR_NUMBER] =
header[SPV_INDEX_MAGIC_NUMBER] = SpvMagicNumber;
header[SPV_INDEX_VERSION_NUMBER] = spvVersionForTargetEnv(env);
header[SPV_INDEX_GENERATOR_NUMBER] =
SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_ASSEMBLER, kAssemblerVersion);
words[SPV_INDEX_BOUND] = bound;
words[SPV_INDEX_SCHEMA] = 0; // NOTE: Reserved
header[SPV_INDEX_BOUND] = bound;
header[SPV_INDEX_SCHEMA] = 0; // NOTE: Reserved
return SPV_SUCCESS;
}
@ -721,7 +717,8 @@ spv_result_t spvTextToBinaryInternal(const libspirv::AssemblyGrammar& grammar,
currentIndex += inst.words.size();
}
if (auto error = SetHeader(data, context.getBound())) return error;
if (auto error = SetHeader(grammar.target_env(), context.getBound(), data))
return error;
spv_binary binary = new spv_binary_t();
if (!binary) {

View File

@ -128,7 +128,7 @@ void DebugInstructionPass(ValidationState_t& _,
void ProcessIds(ValidationState_t& _, const spv_parsed_instruction_t& inst) {
if (inst.result_id) {
_.usedefs().AddDef(
{inst.result_id, inst.type_id, inst.opcode,
{inst.result_id, inst.type_id, static_cast<SpvOp>(inst.opcode),
std::vector<uint32_t>(inst.words, inst.words + inst.num_words)});
}
for (auto op = inst.operands; op != inst.operands + inst.num_operands; ++op) {
@ -140,7 +140,7 @@ spv_result_t ProcessInstruction(void* user_data,
const spv_parsed_instruction_t* inst) {
ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
_.incrementInstructionCount();
if (inst->opcode == SpvOpEntryPoint)
if (static_cast<SpvOp>(inst->opcode) == SpvOpEntryPoint)
_.entry_points().push_back(inst->words[2]);
DebugInstructionPass(_, inst);
@ -203,11 +203,12 @@ spv_result_t spvValidate(const spv_const_context context,
uint64_t index = SPV_INDEX_INSTRUCTION;
while (index < binary->wordCount) {
uint16_t wordCount;
SpvOp opcode;
uint16_t opcode;
spvOpcodeSplit(spvFixWord(binary->code[index], endian), &wordCount,
&opcode);
spv_instruction_t inst;
spvInstructionCopy(&binary->code[index], opcode, wordCount, endian, &inst);
spvInstructionCopy(&binary->code[index], static_cast<SpvOp>(opcode),
wordCount, endian, &inst);
instructions.push_back(inst);
index += wordCount;
}

View File

@ -33,25 +33,24 @@ namespace libspirv {
spv_result_t CfgPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst) {
if (_.getLayoutSection() == kLayoutFunctionDefinitions) {
SpvOp opcode = inst->opcode;
SpvOp opcode = static_cast<SpvOp>(inst->opcode);
switch (opcode) {
case SpvOpLabel:
spvCheckReturn(_.get_functions().RegisterBlock(inst->result_id));
break;
case SpvOpBranch:
case SpvOpBranchConditional:
case SpvOpSwitch:
case SpvOpKill:
case SpvOpReturn:
case SpvOpReturnValue:
case SpvOpUnreachable:
spvCheckReturn(_.get_functions().RegisterBlockEnd());
break;
default:
break;
case SpvOpLabel:
spvCheckReturn(_.get_functions().RegisterBlock(inst->result_id));
break;
case SpvOpBranch:
case SpvOpBranchConditional:
case SpvOpSwitch:
case SpvOpKill:
case SpvOpReturn:
case SpvOpReturnValue:
case SpvOpUnreachable:
spvCheckReturn(_.get_functions().RegisterBlockEnd());
break;
default:
break;
}
}
return SPV_SUCCESS;
}
}

View File

@ -618,10 +618,10 @@ bool idUsage::isValid<SpvOpConstantSampler>(const spv_instruction_t* inst,
// nullability transitively.
bool IsTypeNullable(const std::vector<uint32_t>& instruction,
const UseDefTracker& usedefs) {
SpvOp opcode;
uint16_t opcode;
uint16_t word_count;
spvOpcodeSplit(instruction[0], &word_count, &opcode);
switch (opcode) {
switch (static_cast<SpvOp>(opcode)) {
case SpvOpTypeBool:
case SpvOpTypeInt:
case SpvOpTypeFloat:

View File

@ -83,10 +83,11 @@ namespace libspirv {
spv_result_t CapCheck(ValidationState_t& _,
const spv_parsed_instruction_t* inst) {
spv_opcode_desc opcode_desc;
if (SPV_SUCCESS == _.grammar().lookupOpcode(inst->opcode, &opcode_desc) &&
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
if (SPV_SUCCESS == _.grammar().lookupOpcode(opcode, &opcode_desc) &&
!_.HasAnyOf(opcode_desc->capabilities))
return _.diag(SPV_ERROR_INVALID_CAPABILITY)
<< "Opcode " << spvOpcodeString(inst->opcode)
<< "Opcode " << spvOpcodeString(opcode)
<< " requires one of these capabilities: "
<< ToString(opcode_desc->capabilities, _.grammar());
for (int i = 0; i < inst->num_operands; ++i) {
@ -99,7 +100,7 @@ spv_result_t CapCheck(ValidationState_t& _,
const auto caps =
RequiredCapabilities(_.grammar(), operand.type, mask_bit);
if (!_.HasAnyOf(caps)) {
return CapabilityError(_, i + 1, inst->opcode,
return CapabilityError(_, i + 1, opcode,
ToString(caps, _.grammar()));
}
}
@ -108,8 +109,7 @@ spv_result_t CapCheck(ValidationState_t& _,
// Check the operand word as a whole.
const auto caps = RequiredCapabilities(_.grammar(), operand.type, word);
if (!_.HasAnyOf(caps)) {
return CapabilityError(_, i + 1, inst->opcode,
ToString(caps, _.grammar()));
return CapabilityError(_, i + 1, opcode, ToString(caps, _.grammar()));
}
}
}
@ -118,10 +118,11 @@ spv_result_t CapCheck(ValidationState_t& _,
spv_result_t InstructionPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst) {
if (inst->opcode == SpvOpCapability)
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
if (opcode == SpvOpCapability)
_.registerCapability(
static_cast<SpvCapability>(inst->words[inst->operands[0].offset]));
if (inst->opcode == SpvOpVariable) {
if (opcode == SpvOpVariable) {
const auto storage_class =
static_cast<SpvStorageClass>(inst->words[inst->operands[2].offset]);
if (storage_class == SpvStorageClassGeneric)

View File

@ -182,7 +182,7 @@ namespace libspirv {
// Performs logical layout validation. See Section 2.4
spv_result_t ModuleLayoutPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst) {
SpvOp opcode = inst->opcode;
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
switch (_.getLayoutSection()) {
case kLayoutCapabilities:

View File

@ -99,7 +99,7 @@ namespace libspirv {
spv_result_t SsaPass(ValidationState_t& _,
const spv_parsed_instruction_t* inst) {
auto can_have_forward_declared_ids =
getCanBeForwardDeclaredFunction(inst->opcode);
getCanBeForwardDeclaredFunction(static_cast<SpvOp>(inst->opcode));
for (unsigned i = 0; i < inst->num_operands; i++) {
const spv_parsed_operand_t& operand = inst->operands[i];

View File

@ -28,10 +28,10 @@
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "TestFixture.h"
#include "UnitSPIRV.h"
#include "gmock/gmock.h"
#include "spirv/OpenCL.std.h"
// Returns true if two spv_parsed_operand_t values are equal.
// To use this operator, this definition must appear in the same namespace
@ -60,7 +60,7 @@ using ::testing::_;
struct ParsedInstruction {
explicit ParsedInstruction(const spv_parsed_instruction_t& inst)
: words(inst.words, inst.words + inst.num_words),
opcode(inst.opcode),
opcode(static_cast<SpvOp>(inst.opcode)),
ext_inst_type(inst.ext_inst_type),
type_id(inst.type_id),
result_id(inst.result_id),
@ -463,7 +463,7 @@ INSTANTIATE_TEST_CASE_P(
"Module has incomplete header: only 3 words instead of 5"},
{kHeaderForBound1, 4,
"Module has incomplete header: only 4 words instead of 5"},
}),);
}), );
// A binary parser diagnostic test case where a vector of words is
// provided. We'll use this to express cases that can't be created
@ -696,7 +696,7 @@ INSTANTIATE_TEST_CASE_P(
MakeInstruction(SpvOpConstant, {1, 2, 42}),
}),
"Type Id 1 is not a scalar numeric type"},
}),);
}), );
// A binary parser diagnostic case generated from an assembly text input.
struct AssemblyDiagnosticCase {
@ -766,6 +766,6 @@ INSTANTIATE_TEST_CASE_P(
"Invalid image operand: 511 has invalid mask component 256"},
{"OpSelectionMerge %1 !7",
"Invalid selection control operand: 7 has invalid mask component 4"},
}),);
}), );
} // anonymous namespace

View File

@ -421,8 +421,6 @@ TEST_F(TextToBinaryTest, VersionString) {
Eq(SPV_SUCCESS));
EXPECT_EQ(nullptr, diagnostic);
EXPECT_EQ(1, SPV_SPIRV_VERSION_MAJOR);
EXPECT_EQ(0, SPV_SPIRV_VERSION_MINOR);
EXPECT_THAT(decoded_text->str, HasSubstr("Version: 1.0\n"))
<< EncodeAndDecodeSuccessfully("");
spvTextDestroy(decoded_text);

View File

@ -88,7 +88,6 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES})
${CMAKE_CURRENT_SOURCE_DIR}/Validate.SSA.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ValidateID.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ValidationState.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Version.cpp
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
add_executable(UnitSPIRV ${TEST_SOURCES})

View File

@ -28,6 +28,7 @@
#include <gmock/gmock.h>
#include "TestFixture.h"
#include "spirv/OpenCL.std.h"
namespace {

View File

@ -28,6 +28,7 @@
#include <vector>
#include "UnitSPIRV.h"
#include "spirv/GLSL.std.450.h"
namespace {

View File

@ -31,7 +31,7 @@ namespace {
TEST(OpcodeSplit, Default) {
uint32_t word = spvOpcodeMake(42, (SpvOp)23);
uint16_t wordCount = 0;
SpvOp opcode;
uint16_t opcode;
spvOpcodeSplit(word, &wordCount, &opcode);
ASSERT_EQ(42, wordCount);
ASSERT_EQ(23, opcode);

View File

@ -31,6 +31,8 @@
#include "TestFixture.h"
#include "gmock/gmock.h"
#include "spirv/GLSL.std.450.h"
#include "spirv/OpenCL.std.h"
namespace {

View File

@ -54,7 +54,7 @@ Options:
const char kBuildVersion[] =
#include "build-version.inc"
;
;
int main(int argc, char** argv) {
const char* inFile = nullptr;
@ -88,8 +88,8 @@ int main(int argc, char** argv) {
// Long options
if (0 == strcmp(argv[argi], "--version")) {
printf("%s\n", kBuildVersion);
printf("Target: SPIR-V %d.%d rev %d\n", SPV_SPIRV_VERSION_MAJOR,
SPV_SPIRV_VERSION_MINOR, SPV_SPIRV_VERSION_REVISION);
printf("Target: %s\n",
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0_4));
return 0;
}
if (0 == strcmp(argv[argi], "--help")) {

View File

@ -61,7 +61,7 @@ Options:
const char kBuildVersion[] =
#include "build-version.inc"
;
;
int main(int argc, char** argv) {
const char* inFile = nullptr;
@ -101,8 +101,8 @@ int main(int argc, char** argv) {
return 0;
} else if (0 == strcmp(argv[argi], "--version")) {
printf("%s\n", kBuildVersion);
printf("Target: SPIR-V %d.%d rev %d\n", SPV_SPIRV_VERSION_MAJOR,
SPV_SPIRV_VERSION_MINOR, SPV_SPIRV_VERSION_REVISION);
printf("Target: %s\n",
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0_4));
return 0;
} else {
print_usage(argv[0]);
@ -174,8 +174,7 @@ int main(int argc, char** argv) {
// into the output stream.
// If the printing option is off, then save the text in memory, so
// it can be emitted later in this function.
const bool print_to_stdout =
spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options);
const bool print_to_stdout = SPV_BINARY_TO_TEXT_OPTION_PRINT & options;
spv_text text;
spv_text* textOrNull = print_to_stdout ? nullptr : &text;
spv_diagnostic diagnostic = nullptr;

View File

@ -63,8 +63,9 @@ int main(int argc, char** argv) {
if ('-' == cur_arg[0]) {
if (0 == strcmp(cur_arg, "--version")) {
printf("%s\n", kBuildVersion);
printf("Target: SPIR-V %d.%d rev %d\n", SPV_SPIRV_VERSION_MAJOR,
SPV_SPIRV_VERSION_MINOR, SPV_SPIRV_VERSION_REVISION);
printf("Targets:\n %s\n %s\n",
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0_4),
spvTargetEnvDescription(SPV_ENV_VULKAN_1_0_7));
return 0;
} else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
print_usage(argv[0]);