Refactor Id -> Instruction

This commit is contained in:
Umar Arshad 2016-08-06 13:29:33 -04:00 committed by David Neto
parent d49928f0cc
commit 816f29805b
11 changed files with 274 additions and 240 deletions

View File

@ -170,7 +170,7 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/val/BasicBlock.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/Construct.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/Function.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/Id.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/Instruction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/ValidationState.cpp)
# The software_version.cpp file includes build-version.inc.

View File

@ -1,135 +0,0 @@
// 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
// "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.
#ifndef LIBSPIRV_VAL_ID_H_
#define LIBSPIRV_VAL_ID_H_
#include <cstdint>
#include <functional>
#include <set>
#include "spirv-tools/libspirv.h"
#include "val/Function.h"
namespace libspirv {
class BasicBlock;
/// Represents a definition of any ID
///
/// This class represents the a definition of an Id in a module. This object can
/// be formed as a complete, or incomplete Id. A complete Id allows you to
/// reference all of the properties of this class and forms a fully defined
/// object in the module. The incomplete Id is defined only by its integer value
/// in a module and can only be used to search in a data structure.
class Id {
public:
/// This constructor creates an incomplete Id. This constructor can be used to
/// create Id that are used to find other Ids
explicit Id(const uint32_t result_id = 0);
/// This constructor creates a complete Id.
explicit Id(const spv_parsed_instruction_t* inst,
Function* function = nullptr, BasicBlock* block = nullptr);
/// Registers a use of the Id
void RegisterUse(const BasicBlock* block = nullptr);
/// returns the id of the Id
operator uint32_t() const { return id_; }
uint32_t id() const { return id_; }
uint32_t type_id() const { return type_id_; }
SpvOp opcode() const { return opcode_; }
/// returns the Function where the id was defined. nullptr if it was defined
/// outside of a Function
const Function* defining_function() const { return defining_function_; }
/// returns the BasicBlock where the id was defined. nullptr if it was defined
/// outside of a BasicBlock
const BasicBlock* defining_block() const { return defining_block_; }
/// Returns the set of blocks where this Id was used
const std::set<const BasicBlock*>& uses() const { return uses_; }
/// The words used to define the Id
const std::vector<uint32_t>& words() const { return words_; }
private:
/// The integer that identifies the Id
uint32_t id_;
/// The type of the Id
uint32_t type_id_;
/// The opcode used to define the Id
SpvOp opcode_;
/// The function in which the Id was defined
Function* defining_function_;
/// The block in which the Id was defined
BasicBlock* defining_block_;
/// The blocks in which the Id was used
std::set<const BasicBlock*> uses_;
/// The words of the instuction that defined the Id
std::vector<uint32_t> words_;
#define OPERATOR(OP) \
friend bool operator OP(const Id& lhs, const Id& rhs); \
friend bool operator OP(const Id& lhs, uint32_t rhs)
OPERATOR(<);
OPERATOR(==);
#undef OPERATOR
};
#define OPERATOR(OP) \
bool operator OP(const Id& lhs, const Id& rhs); \
bool operator OP(const Id& lhs, uint32_t rhs)
OPERATOR(<);
OPERATOR(==);
#undef OPERATOR
} // namespace libspirv
// custom specialization of std::hash for Id
namespace std {
template <>
struct hash<libspirv::Id> {
typedef libspirv::Id argument_type;
typedef std::size_t result_type;
result_type operator()(const argument_type& id) const {
return hash<uint32_t>()(id);
}
};
} /// namespace std
#endif // LIBSPIRV_VAL_ID_H_

View File

@ -24,39 +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 "val/Id.h"
#include "val/Instruction.h"
#include <utility>
using std::make_pair;
namespace libspirv {
#define OPERATOR(OP) \
bool operator OP(const Id& lhs, const Id& rhs) { \
return lhs.id_ OP rhs.id_; \
} \
bool operator OP(const Id& lhs, uint32_t rhs) { return lhs.id_ OP rhs; }
#define OPERATOR(OP) \
bool operator OP(const Instruction& lhs, const Instruction& rhs) { \
return lhs.id() OP rhs.id(); \
} \
bool operator OP(const Instruction& lhs, uint32_t rhs) { \
return lhs.id() OP rhs; \
}
OPERATOR(<)
OPERATOR(==)
#undef OPERATOR
Id::Id(const uint32_t result_id)
: id_(result_id),
type_id_(0),
opcode_(SpvOpNop),
defining_function_(nullptr),
defining_block_(nullptr),
uses_(),
words_(0) {}
Instruction::Instruction(const spv_parsed_instruction_t* inst,
Function* defining_function,
BasicBlock* defining_block)
: words_(inst->words, inst->words + inst->num_words),
operands_(inst->operands, inst->operands + inst->num_operands),
inst_({words_.data(), inst->num_words, inst->opcode, inst->ext_inst_type,
inst->type_id, inst->result_id, operands_.data(),
inst->num_operands}),
function_(defining_function),
block_(defining_block),
uses_() {}
Id::Id(const spv_parsed_instruction_t* inst, Function* function,
BasicBlock* block)
: id_(inst->result_id),
type_id_(inst->type_id),
opcode_(static_cast<SpvOp>(inst->opcode)),
defining_function_(function),
defining_block_(block),
uses_(),
words_(inst->words, inst->words + inst->num_words) {}
void Id::RegisterUse(const BasicBlock* block) {
if (block) { uses_.insert(block); }
void Instruction::RegisterUse(const Instruction* inst, uint32_t index) {
uses_.push_back(make_pair(inst, index));
}
} // namespace libspirv

131
source/val/Instruction.h Normal file
View File

@ -0,0 +1,131 @@
// 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
// "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.
#ifndef LIBSPIRV_VAL_INSTRUCTION_H_
#define LIBSPIRV_VAL_INSTRUCTION_H_
#include <cstdint>
#include <functional>
#include <utility>
#include <vector>
#include "spirv-tools/libspirv.h"
#include "table.h"
namespace libspirv {
class BasicBlock;
class Function;
/// Wraps the spv_parsed_instruction struct along with use and definition of the
/// instruction's result id
class Instruction {
public:
explicit Instruction(const spv_parsed_instruction_t* inst,
Function* defining_function = nullptr,
BasicBlock* defining_block = nullptr);
/// Registers the use of the Instruction in instruction \p inst at \p index
void RegisterUse(const Instruction* inst, uint32_t index);
uint32_t id() const { return inst_.result_id; }
uint32_t type_id() const { return inst_.type_id; }
SpvOp opcode() const { return static_cast<SpvOp>(inst_.opcode); }
/// Returns the Function where the instruction was defined. nullptr if it was
/// defined outside of a Function
const Function* function() const { return function_; }
/// Returns the BasicBlock where the instruction was defined. nullptr if it
/// was defined outside of a BasicBlock
const BasicBlock* block() const { return block_; }
/// Returns a vector of pairs of all references to this instruction's result
/// id. The first element is the instruction in which this result id was
/// referenced and the second is the index of the word in that instruction
/// where this result id appeared
const std::vector<std::pair<const Instruction*, uint32_t>>& uses() const {
return uses_;
}
/// The word used to define the Instruction
uint32_t words(size_t index) const { return words_[index]; }
/// The words used to define the Instruction
const std::vector<uint32_t>& words() const { return words_; }
/// The operand of the Instruction at \p index
const spv_parsed_operand_t& operands(size_t index) const {
return operands_[index];
}
/// The operands of the Instruction
const std::vector<spv_parsed_operand_t>& operands() const {
return operands_;
}
private:
const std::vector<uint32_t> words_;
const std::vector<spv_parsed_operand_t> operands_;
spv_parsed_instruction_t inst_;
/// The function in which this instruction was declared
Function* function_;
/// The basic block in which this instruction was declared
BasicBlock* block_;
/// This is a vector of pairs of all references to this instruction's result
/// id. The first element is the instruction in which this result id was
/// referenced and the second is the index of the word in the referencing
/// instruction where this instruction appeared
std::vector<std::pair<const Instruction*, uint32_t>> uses_;
};
#define OPERATOR(OP) \
bool operator OP(const Instruction& lhs, const Instruction& rhs); \
bool operator OP(const Instruction& lhs, uint32_t rhs)
OPERATOR(<);
OPERATOR(==);
#undef OPERATOR
} // namespace libspirv
// custom specialization of std::hash for Instruction
namespace std {
template <>
struct hash<libspirv::Instruction> {
typedef libspirv::Instruction argument_type;
typedef std::size_t result_type;
result_type operator()(const argument_type& inst) const {
return hash<uint32_t>()(inst.id());
}
};
} /// namespace std
#endif // LIBSPIRV_VAL_INSTRUCTION_H_

View File

@ -202,6 +202,8 @@ ValidationState_t::ValidationState_t(spv_diagnostic* diagnostic,
current_layout_section_(kLayoutCapabilities),
module_functions_(),
module_capabilities_(0u),
ordered_instructions_(),
all_definitions_(),
grammar_(context),
addressing_model_(SpvAddressingModelLogical),
memory_model_(SpvMemoryModelSimple),
@ -251,20 +253,25 @@ vector<uint32_t> ValidationState_t::UnresolvedForwardIds() const {
}
bool ValidationState_t::IsDefinedId(uint32_t id) const {
return all_definitions_.find(Id{id}) != end(all_definitions_);
return all_definitions_.find(id) != end(all_definitions_);
}
const Id* ValidationState_t::FindDef(uint32_t id) const {
if (all_definitions_.count(Id{id}) == 0) {
const Instruction* ValidationState_t::FindDef(uint32_t id) const {
if (all_definitions_.count(id) == 0) {
return nullptr;
} else {
/// We are in a const function, so we cannot use defs.operator[]().
/// Luckily we know the key exists, so defs_.at() won't throw an
/// exception.
return &all_definitions_.at(id);
return all_definitions_.at(id);
}
}
Instruction* ValidationState_t::FindDef(uint32_t id) {
return const_cast<Instruction*>(
const_cast<const ValidationState_t*>(this)->FindDef(id));
}
// Increments the instruction count. Used for diagnostic
int ValidationState_t::increment_instruction_count() {
return instruction_counter_++;
@ -370,26 +377,17 @@ spv_result_t ValidationState_t::RegisterFunctionEnd() {
return SPV_SUCCESS;
}
void ValidationState_t::AddId(const spv_parsed_instruction_t& inst) {
void ValidationState_t::RegisterInstruction(
const spv_parsed_instruction_t& inst) {
if (in_function_body()) {
if (in_block()) {
all_definitions_[inst.result_id] =
Id{&inst, &current_function(), current_function().current_block()};
} else {
all_definitions_[inst.result_id] = Id{&inst, &current_function()};
}
ordered_instructions_.emplace_back(
&inst, &current_function(), current_function().current_block());
} else {
all_definitions_[inst.result_id] = Id{&inst};
ordered_instructions_.emplace_back(&inst, nullptr, nullptr);
}
}
void ValidationState_t::RegisterUseId(uint32_t used_id) {
auto used = all_definitions_.find(used_id);
if (used != end(all_definitions_)) {
if (in_function_body())
used->second.RegisterUse(current_function().current_block());
else
used->second.RegisterUse(nullptr);
uint32_t id = ordered_instructions_.back().id();
if (id) {
all_definitions_.insert(make_pair(id, &ordered_instructions_.back()));
}
}
} /// namespace libspirv

View File

@ -28,7 +28,6 @@
#define LIBSPIRV_VAL_VALIDATIONSTATE_H_
#include <list>
#include <map>
#include <string>
#include <unordered_map>
#include <unordered_set>
@ -40,7 +39,7 @@
#include "spirv/1.1/spirv.h"
#include "spirv_definition.h"
#include "val/Function.h"
#include "val/Id.h"
#include "val/Instruction.h"
namespace libspirv {
@ -160,17 +159,24 @@ class ValidationState_t {
AssemblyGrammar& grammar() { return grammar_; }
/// Adds an id to the module
void AddId(const spv_parsed_instruction_t& inst);
/// Register Id use
void RegisterUseId(uint32_t used_id);
/// Registers the instruction
void RegisterInstruction(const spv_parsed_instruction_t& inst);
/// Finds id's def, if it exists. If found, returns the definition otherwise
/// nullptr
const Id* FindDef(uint32_t id) const;
const Instruction* FindDef(uint32_t id) const;
const std::unordered_map<uint32_t, Id>& all_definitions() const {
/// Finds id's def, if it exists. If found, returns the definition otherwise
/// nullptr
Instruction* FindDef(uint32_t id);
/// Returns a vector of instructions in the order they appear in the binary
const std::list<Instruction>& ordered_instructions() {
return ordered_instructions_;
}
/// Returns a map of instructions mapped by their result id
const std::unordered_map<uint32_t, Instruction*>& all_definitions() const {
return all_definitions_;
}
@ -185,7 +191,7 @@ class ValidationState_t {
std::unordered_set<uint32_t> unresolved_forward_ids_;
/// A map of operand IDs and their names defined by the OpName instruction
std::map<uint32_t, std::string> operand_names_;
std::unordered_map<uint32_t, std::string> operand_names_;
/// The section of the code being processed
ModuleLayoutSection current_layout_section_;
@ -197,7 +203,11 @@ class ValidationState_t {
spv_capability_mask_t
module_capabilities_; /// Module's declared capabilities.
std::unordered_map<uint32_t, Id> all_definitions_;
/// List of all instructions in the order they appear in the binary
std::list<Instruction> ordered_instructions_;
/// Instructions that can be referenced by Ids
std::unordered_map<uint32_t, Instruction*> all_definitions_;
/// IDs that are entry points, ie, arguments to OpEntryPoint.
std::vector<uint32_t> entry_points_;

View File

@ -229,6 +229,7 @@ spv_result_t spvValidate(const spv_const_context context,
// CFG checks are performed after the binary has been parsed
// and the CFGPass has collected information about the control flow
spvCheckReturn(PerformCfgChecks(vstate));
spvCheckReturn(UpdateIdUse(vstate));
spvCheckReturn(CheckIdDefinitionDominateUse(vstate));
// NOTE: Copy each instruction for easier processing

View File

@ -101,6 +101,16 @@ std::vector<std::pair<BasicBlock*, BasicBlock*>> CalculateDominators(
/// @return SPV_SUCCESS if no errors are found. SPV_ERROR_INVALID_CFG otherwise
spv_result_t PerformCfgChecks(ValidationState_t& _);
/// @brief Updates the use vectors of all instructions that can be referenced
///
/// This function will update the vector which define where an instruction was
/// referenced in the binary.
///
/// @param[in] _ the validation state of the module
///
/// @return SPV_SUCCESS if no errors are found.
spv_result_t UpdateIdUse(ValidationState_t& _);
/// @brief This function checks all ID definitions dominate their use in the
/// CFG.
///

View File

@ -51,7 +51,6 @@ using std::make_pair;
using std::make_tuple;
using std::numeric_limits;
using std::pair;
using std::set;
using std::string;
using std::tie;
using std::transform;

View File

@ -30,13 +30,15 @@
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "diagnostic.h"
#include "instruction.h"
#include "opcode.h"
#include "spirv-tools/libspirv.h"
#include "val/Function.h"
#include "val/ValidationState.h"
#define spvCheck(condition, action) \
@ -47,6 +49,10 @@
using libspirv::ValidationState_t;
using std::function;
using std::ignore;
using std::make_pair;
using std::pair;
using std::unordered_set;
using std::vector;
namespace {
@ -58,9 +64,8 @@ class idUsage {
const spv_instruction_t* pInsts, const uint64_t instCountArg,
const SpvMemoryModel memoryModelArg,
const SpvAddressingModel addressingModelArg,
const ValidationState_t& module,
const std::vector<uint32_t>& entry_points, spv_position positionArg,
spv_diagnostic* pDiagnosticArg)
const ValidationState_t& module, const vector<uint32_t>& entry_points,
spv_position positionArg, spv_diagnostic* pDiagnosticArg)
: opcodeTable(opcodeTableArg),
operandTable(operandTableArg),
extInstTable(extInstTableArg),
@ -89,7 +94,7 @@ class idUsage {
spv_position position;
spv_diagnostic* pDiagnostic;
const ValidationState_t& module_;
std::vector<uint32_t> entry_points_;
vector<uint32_t> entry_points_;
};
#define DIAG(INDEX) \
@ -278,8 +283,8 @@ bool idUsage::isValid<SpvOpTypeSampler>(const spv_instruction_t*,
// constant-defining instruction (either OpConstant or
// OpSpecConstant). typeWords are the words of the constant's-type-defining
// OpTypeInt.
bool aboveZero(const std::vector<uint32_t>& constWords,
const std::vector<uint32_t>& typeWords) {
bool aboveZero(const vector<uint32_t>& constWords,
const vector<uint32_t>& typeWords) {
const uint32_t width = typeWords[2];
const bool is_signed = typeWords[3] > 0;
const uint32_t loWord = constWords[3];
@ -630,7 +635,7 @@ bool idUsage::isValid<SpvOpConstantSampler>(const spv_instruction_t* inst,
// True if instruction defines a type that can have a null value, as defined by
// the SPIR-V spec. Tracks composite-type components through module to check
// nullability transitively.
bool IsTypeNullable(const std::vector<uint32_t>& instruction,
bool IsTypeNullable(const vector<uint32_t>& instruction,
const ValidationState_t& module) {
uint16_t opcode;
uint16_t word_count;
@ -2377,6 +2382,29 @@ function<bool(unsigned)> getCanBeForwardDeclaredFunction(SpvOp opcode) {
namespace libspirv {
spv_result_t UpdateIdUse(ValidationState_t& _) {
for (const auto& inst : _.ordered_instructions()) {
for (auto& operand : inst.operands()) {
const spv_operand_type_t& type = operand.type;
const uint32_t operand_id = inst.words()[operand.offset];
switch (type) {
case SPV_OPERAND_TYPE_VARIABLE_ID:
case SPV_OPERAND_TYPE_ID:
case SPV_OPERAND_TYPE_TYPE_ID:
case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
case SPV_OPERAND_TYPE_SCOPE_ID:
if (auto def = _.FindDef(operand_id))
def->RegisterUse(&inst, operand.offset);
break;
default:
break;
}
}
}
return SPV_SUCCESS;
}
/// This function checks all ID definitions dominate their use in the CFG.
///
/// This function will iterate over all ID definitions that are defined in the
@ -2387,32 +2415,38 @@ namespace libspirv {
/// checked during the initial binary parse in the IdPass below
spv_result_t CheckIdDefinitionDominateUse(const ValidationState_t& _) {
for (const auto& definition : _.all_definitions()) {
// Check only those blocks defined in a function
if (const Function* func = definition.second.defining_function()) {
if (const BasicBlock* block = definition.second.defining_block()) {
// Check only those definitions defined in a function
if (const Function* func = definition.second->function()) {
if (const BasicBlock* block = definition.second->block()) {
if (!block->reachable()) continue;
// If the Id is defined within a block then make sure all references to
// that Id appear in a blocks that are dominated by the defining block
for (auto use : definition.second.uses()) {
if (!use->reachable()) continue;
if (use->dom_end() == find(use->dom_begin(), use->dom_end(), block)) {
return _.diag(SPV_ERROR_INVALID_ID)
<< "ID " << _.getIdName(definition.first)
<< " defined in block " << _.getIdName(block->id())
<< " does not dominate its use in block "
<< _.getIdName(use->id());
for (auto& use_index_pair : definition.second->uses()) {
const Instruction* use = use_index_pair.first;
if (const BasicBlock* use_block = use->block()) {
if (!use_block->reachable()) continue;
if (use->opcode() != SpvOpPhi &&
use_block->dom_end() ==
find(use_block->dom_begin(), use_block->dom_end(), block)) {
return _.diag(SPV_ERROR_INVALID_ID)
<< "ID " << _.getIdName(definition.first)
<< " defined in block " << _.getIdName(block->id())
<< " does not dominate its use in block "
<< _.getIdName(use_block->id());
}
}
}
} else {
// If the Ids defined within a function but not in a block(i.e. function
// parameters, block ids), then make sure all references to that Id
// appear within the same function
bool found = false;
for (auto use : definition.second.uses()) {
tie(ignore, found) = func->GetBlock(use->id());
if (!found) {
for (auto use : definition.second->uses()) {
const Instruction* inst = use.first;
if (inst->function() && inst->function() != func) {
return _.diag(SPV_ERROR_INVALID_ID)
<< "ID " << _.getIdName(definition.first)
<< " used in block " << _.getIdName(use->id())
<< " used in function "
<< _.getIdName(inst->function()->id())
<< " is used outside of it's defining function "
<< _.getIdName(func->id());
}
@ -2455,17 +2489,6 @@ spv_result_t IdPass(ValidationState_t& _,
case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
case SPV_OPERAND_TYPE_SCOPE_ID:
if (_.IsDefinedId(*operand_ptr)) {
if (inst->opcode == SpvOpPhi && i > 1) {
// For now, ignore uses of IDs as arguments to OpPhi, since
// the job of an OpPhi is to allow a block to use an ID from a
// block that doesn't dominate the use.
// We only track usage by a particular block, rather than
// which instruction and operand number is using the value, so
// we have to just bluntly avod tracking the use here.
// Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/286
} else {
_.RegisterUseId(*operand_ptr);
}
ret = SPV_SUCCESS;
} else if (can_have_forward_declared_ids(i)) {
ret = _.ForwardDeclareId(*operand_ptr);
@ -2483,9 +2506,7 @@ spv_result_t IdPass(ValidationState_t& _,
return ret;
}
}
if (inst->result_id) {
_.AddId(*inst);
}
_.RegisterInstruction(*inst);
return SPV_SUCCESS;
}
} // namespace libspirv

View File

@ -1234,9 +1234,9 @@ TEST_F(ValidateSSA, DISABLED_PhiVariableDefMustComeFromBlockDominatingThePredece
// TODO(dneto): Check for a good error message
}
TEST_F(ValidateSSA, DominanceCheckIgnoresUsesInUnreachableBlocksDefInBlockGood) {
string str = kHeader
+ kBasicTypes +
TEST_F(ValidateSSA,
DominanceCheckIgnoresUsesInUnreachableBlocksDefInBlockGood) {
string str = kHeader + kBasicTypes +
R"(
%func = OpFunction %voidt None %vfunct
%entry = OpLabel
@ -1253,7 +1253,8 @@ TEST_F(ValidateSSA, DominanceCheckIgnoresUsesInUnreachableBlocksDefInBlockGood)
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
}
TEST_F(ValidateSSA, DominanceCheckIgnoresUsesInUnreachableBlocksDefIsParamGood) {
TEST_F(ValidateSSA,
DominanceCheckIgnoresUsesInUnreachableBlocksDefIsParamGood) {
string str = kHeader + kBasicTypes +
R"(
%void_fn_int = OpTypeFunction %voidt %intt
@ -1275,9 +1276,8 @@ TEST_F(ValidateSSA, DominanceCheckIgnoresUsesInUnreachableBlocksDefIsParamGood)
TEST_F(ValidateSSA, UseFunctionParameterFromOtherFunctionBad) {
string str = kHeader +
"OpName %first \"first\"\n"
"OpName %entry2 \"entry2\"\n"
"OpName %func \"func\"\n" +
kBasicTypes +
"OpName %func2 \"func2\"\n" + kBasicTypes +
R"(
%viifunct = OpTypeFunction %voidt %intt %intt
%func = OpFunction %voidt None %viifunct
@ -1297,7 +1297,7 @@ TEST_F(ValidateSSA, UseFunctionParameterFromOtherFunctionBad) {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
MatchesRegex("ID .\\[first\\] used in block .\\[entry2\\] is used "
MatchesRegex("ID .\\[first\\] used in function .\\[func2\\] is used "
"outside of it's defining function .\\[func\\]"));
}
// TODO(umar): OpGroupMemberDecorate