Re-format files in source, source/opt, source/util, source/val and tools.

NFC. This just makes sure every file is formatted following the
formatting definition in .clang-format.

Re-formatted with:

$ clang-format -i $(find source tools include -name '*.cpp')
$ clang-format -i $(find source tools include -name '*.h')
This commit is contained in:
Diego Novillo 2017-11-08 12:40:02 -05:00
parent f32d11f74b
commit d2938e4842
120 changed files with 2586 additions and 2997 deletions

View File

@ -179,12 +179,11 @@ class Parser {
word_index(0),
endian(),
requires_endian_conversion(false) {
// Temporary storage for parser state within a single instruction.
// Most instructions require fewer than 25 words or operands.
operands.reserve(25);
endian_converted_words.reserve(25);
expected_operands.reserve(25);
// Temporary storage for parser state within a single instruction.
// Most instructions require fewer than 25 words or operands.
operands.reserve(25);
endian_converted_words.reserve(25);
expected_operands.reserve(25);
}
State() : State(0, 0, nullptr) {}
const uint32_t* words; // Words in the binary SPIR-V module.
@ -310,7 +309,8 @@ spv_result_t Parser::parseInstruction() {
// own operands depending on the selected extended instruction.
_.expected_operands.clear();
for (auto i = 0; i < opcode_desc->numTypes; i++)
_.expected_operands.push_back(opcode_desc->operandTypes[opcode_desc->numTypes - i - 1]);
_.expected_operands.push_back(
opcode_desc->operandTypes[opcode_desc->numTypes - i - 1]);
while (_.word_index < inst_offset + inst_word_count) {
const uint16_t inst_word_index = uint16_t(_.word_index - inst_offset);
@ -323,7 +323,8 @@ spv_result_t Parser::parseInstruction() {
<< inst_word_count << ".";
}
spv_operand_type_t type = spvTakeFirstMatchableOperand(&_.expected_operands);
spv_operand_type_t type =
spvTakeFirstMatchableOperand(&_.expected_operands);
if (auto error =
parseOperand(inst_offset, &inst, type, &_.endian_converted_words,
@ -355,7 +356,8 @@ spv_result_t Parser::parseInstruction() {
// word.
assert(!_.requires_endian_conversion ||
(inst_word_count == _.endian_converted_words.size()));
assert(_.requires_endian_conversion || (_.endian_converted_words.size() == 1));
assert(_.requires_endian_conversion ||
(_.endian_converted_words.size() == 1));
recordNumberType(inst_offset, &inst);
@ -430,8 +432,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
// Save the result ID to type ID mapping.
// In the grammar, type ID always appears before result ID.
if (_.id_to_type_id.find(inst->result_id) != _.id_to_type_id.end())
return diagnostic(SPV_ERROR_INVALID_ID) << "Id " << inst->result_id
<< " is defined more than once";
return diagnostic(SPV_ERROR_INVALID_ID)
<< "Id " << inst->result_id << " is defined more than once";
// Record it.
// 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
@ -477,8 +479,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
assert(SpvOpSpecConstantOp == opcode);
if (grammar_.lookupSpecConstantOpcode(SpvOp(word))) {
return diagnostic() << "Invalid " << spvOperandTypeStr(type) << ": "
<< word;
return diagnostic()
<< "Invalid " << spvOperandTypeStr(type) << ": " << word;
}
spv_opcode_desc opcode_entry = nullptr;
if (grammar_.lookupOpcode(SpvOp(word), &opcode_entry)) {
@ -581,8 +583,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
const spv_ext_inst_type_t ext_inst_type =
spvExtInstImportTypeGet(string);
if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) {
return diagnostic() << "Invalid extended instruction import '"
<< string << "'";
return diagnostic()
<< "Invalid extended instruction import '" << string << "'";
}
// We must have parsed a valid result ID. It's a condition
// of the grammar, and we only accept non-zero result Ids.
@ -620,9 +622,9 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
spv_operand_desc entry;
if (grammar_.lookupOperand(type, word, &entry)) {
return diagnostic() << "Invalid "
<< spvOperandTypeStr(parsed_operand.type)
<< " operand: " << word;
return diagnostic()
<< "Invalid " << spvOperandTypeStr(parsed_operand.type)
<< " operand: " << word;
}
// Prepare to accept operands to this operand, if needed.
spvPushOperandTypes(entry->operandTypes, expected_operands);

View File

@ -17,9 +17,9 @@
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <functional>
#include <map>
#include <cstdint>
#include <unordered_map>
#include <unordered_set>
#include <utility>
@ -36,12 +36,12 @@ using std::vector;
namespace spvtools {
// Control Flow Analysis of control flow graphs of basic block nodes |BB|.
template<class BB> class CFA {
template <class BB>
class CFA {
using bb_ptr = BB*;
using cbb_ptr = const BB*;
using bb_iter = typename std::vector<BB*>::const_iterator;
using get_blocks_func =
std::function<const std::vector<BB*>*(const BB*)>;
using get_blocks_func = std::function<const std::vector<BB*>*(const BB*)>;
struct block_info {
cbb_ptr block; ///< pointer to the block
@ -50,15 +50,16 @@ template<class BB> class CFA {
/// Returns true if a block with @p id is found in the @p work_list vector
///
/// @param[in] work_list Set of blocks visited in the the depth first traversal
/// @param[in] work_list Set of blocks visited in the the depth first
/// traversal
/// of the CFG
/// @param[in] id The ID of the block being checked
///
/// @return true if the edge work_list.back().block->id() => id is a back-edge
static bool FindInWorkList(
const std::vector<block_info>& work_list, uint32_t id);
static bool FindInWorkList(const std::vector<block_info>& work_list,
uint32_t id);
public:
public:
/// @brief Depth first traversal starting from the \p entry BasicBlock
///
/// This function performs a depth first traversal from the \p entry
@ -75,15 +76,16 @@ public:
/// CFG following postorder traversal semantics
/// @param[in] backedge A function that will be called when a backedge is
/// encountered during a traversal
/// NOTE: The @p successor_func and predecessor_func each return a pointer to a
/// NOTE: The @p successor_func and predecessor_func each return a pointer to
/// a
/// collection such that iterators to that collection remain valid for the
/// lifetime of the algorithm.
static void DepthFirstTraversal(const BB* entry,
get_blocks_func successor_func,
std::function<void(cbb_ptr)> preorder,
std::function<void(cbb_ptr)> postorder,
std::function<void(cbb_ptr, cbb_ptr)> backedge);
static void DepthFirstTraversal(
const BB* entry, get_blocks_func successor_func,
std::function<void(cbb_ptr)> preorder,
std::function<void(cbb_ptr)> postorder,
std::function<void(cbb_ptr, cbb_ptr)> backedge);
/// @brief Calculates dominator edges for a set of blocks
///
/// Computes dominators using the algorithm of Cooper, Harvey, and Kennedy
@ -92,54 +94,58 @@ public:
/// The algorithm assumes there is a unique root node (a node without
/// predecessors), and it is therefore at the end of the postorder vector.
///
/// This function calculates the dominator edges for a set of blocks in the CFG.
/// This function calculates the dominator edges for a set of blocks in the
/// CFG.
/// Uses the dominator algorithm by Cooper et al.
///
/// @param[in] postorder A vector of blocks in post order traversal order
/// @param[in] postorder A vector of blocks in post order traversal
/// order
/// in a CFG
/// @param[in] predecessor_func Function used to get the predecessor nodes of a
/// @param[in] predecessor_func Function used to get the predecessor nodes of
/// a
/// block
///
/// @return the dominator tree of the graph, as a vector of pairs of nodes.
/// The first node in the pair is a node in the graph. The second node in the
/// pair is its immediate dominator in the sense of Cooper et.al., where a block
/// without predecessors (such as the root node) is its own immediate dominator.
/// pair is its immediate dominator in the sense of Cooper et.al., where a
/// block
/// without predecessors (such as the root node) is its own immediate
/// dominator.
static vector<pair<BB*, BB*>> CalculateDominators(
const vector<cbb_ptr>& postorder, get_blocks_func predecessor_func);
const vector<cbb_ptr>& postorder, get_blocks_func predecessor_func);
// Computes a minimal set of root nodes required to traverse, in the forward
// direction, the CFG represented by the given vector of blocks, and successor
// and predecessor functions. When considering adding two nodes, each having
// predecessors, favour using the one that appears earlier on the input blocks
// list.
static std::vector<BB*> TraversalRoots(
const std::vector<BB*>& blocks,
get_blocks_func succ_func,
get_blocks_func pred_func);
static std::vector<BB*> TraversalRoots(const std::vector<BB*>& blocks,
get_blocks_func succ_func,
get_blocks_func pred_func);
static void ComputeAugmentedCFG(
std::vector<BB*>& ordered_blocks,
BB* pseudo_entry_block,
BB* pseudo_exit_block,
std::unordered_map<const BB*, std::vector<BB*>>* augmented_successors_map,
std::unordered_map<const BB*, std::vector<BB*>>* augmented_predecessors_map,
get_blocks_func succ_func,
get_blocks_func pred_func);
std::vector<BB*>& ordered_blocks, BB* pseudo_entry_block,
BB* pseudo_exit_block,
std::unordered_map<const BB*, std::vector<BB*>>* augmented_successors_map,
std::unordered_map<const BB*, std::vector<BB*>>*
augmented_predecessors_map,
get_blocks_func succ_func, get_blocks_func pred_func);
};
template<class BB> bool CFA<BB>::FindInWorkList(const vector<block_info>& work_list,
uint32_t id) {
template <class BB>
bool CFA<BB>::FindInWorkList(const vector<block_info>& work_list, uint32_t id) {
for (const auto b : work_list) {
if (b.block->id() == id) return true;
}
return false;
}
template<class BB> void CFA<BB>::DepthFirstTraversal(const BB* entry,
get_blocks_func successor_func,
function<void(cbb_ptr)> preorder,
function<void(cbb_ptr)> postorder,
function<void(cbb_ptr, cbb_ptr)> backedge) {
template <class BB>
void CFA<BB>::DepthFirstTraversal(const BB* entry,
get_blocks_func successor_func,
function<void(cbb_ptr)> preorder,
function<void(cbb_ptr)> postorder,
function<void(cbb_ptr, cbb_ptr)> backedge) {
unordered_set<uint32_t> processed;
/// NOTE: work_list is the sequence of nodes from the root node to the node
@ -147,7 +153,7 @@ template<class BB> void CFA<BB>::DepthFirstTraversal(const BB* entry,
vector<block_info> work_list;
work_list.reserve(10);
work_list.push_back({ entry, begin(*successor_func(entry)) });
work_list.push_back({entry, begin(*successor_func(entry))});
preorder(entry);
processed.insert(entry->id());
@ -156,8 +162,7 @@ template<class BB> void CFA<BB>::DepthFirstTraversal(const BB* entry,
if (top.iter == end(*successor_func(top.block))) {
postorder(top.block);
work_list.pop_back();
}
else {
} else {
BB* child = *top.iter;
top.iter++;
if (FindInWorkList(work_list, child->id())) {
@ -166,16 +171,16 @@ template<class BB> void CFA<BB>::DepthFirstTraversal(const BB* entry,
if (processed.count(child->id()) == 0) {
preorder(child);
work_list.emplace_back(
block_info{ child, begin(*successor_func(child)) });
block_info{child, begin(*successor_func(child))});
processed.insert(child->id());
}
}
}
}
template<class BB>
template <class BB>
vector<pair<BB*, BB*>> CFA<BB>::CalculateDominators(
const vector<cbb_ptr>& postorder, get_blocks_func predecessor_func) {
const vector<cbb_ptr>& postorder, get_blocks_func predecessor_func) {
struct block_detail {
size_t dominator; ///< The index of blocks's dominator in post order array
size_t postorder_index; ///< The index of the block in the post order array
@ -184,7 +189,7 @@ vector<pair<BB*, BB*>> CFA<BB>::CalculateDominators(
unordered_map<cbb_ptr, block_detail> idoms;
for (size_t i = 0; i < postorder.size(); i++) {
idoms[postorder[i]] = { undefined_dom, i };
idoms[postorder[i]] = {undefined_dom, i};
}
idoms[postorder.back()].dominator = idoms[postorder.back()].postorder_index;
@ -196,10 +201,10 @@ vector<pair<BB*, BB*>> CFA<BB>::CalculateDominators(
// Find the first processed/reachable predecessor that is reachable
// in the forward traversal.
auto res = find_if(begin(predecessors), end(predecessors),
[&idoms, undefined_dom](BB* pred) {
return idoms.count(pred) &&
idoms[pred].dominator != undefined_dom;
});
[&idoms, undefined_dom](BB* pred) {
return idoms.count(pred) &&
idoms[pred].dominator != undefined_dom;
});
if (res == end(predecessors)) continue;
const BB* idom = *res;
size_t idom_idx = idoms[idom].postorder_index;
@ -236,17 +241,16 @@ vector<pair<BB*, BB*>> CFA<BB>::CalculateDominators(
for (auto idom : idoms) {
// NOTE: performing a const cast for convenient usage with
// UpdateImmediateDominators
out.push_back({ const_cast<BB*>(get<0>(idom)),
const_cast<BB*>(postorder[get<1>(idom).dominator]) });
out.push_back({const_cast<BB*>(get<0>(idom)),
const_cast<BB*>(postorder[get<1>(idom).dominator])});
}
return out;
}
template<class BB>
std::vector<BB*> CFA<BB>::TraversalRoots(
const std::vector<BB*>& blocks,
get_blocks_func succ_func,
get_blocks_func pred_func) {
template <class BB>
std::vector<BB*> CFA<BB>::TraversalRoots(const std::vector<BB*>& blocks,
get_blocks_func succ_func,
get_blocks_func pred_func) {
// The set of nodes which have been visited from any of the roots so far.
std::unordered_set<const BB*> visited;
@ -254,11 +258,10 @@ std::vector<BB*> CFA<BB>::TraversalRoots(
auto ignore_block = [](const BB*) {};
auto ignore_blocks = [](const BB*, const BB*) {};
auto traverse_from_root = [&mark_visited, &succ_func, &ignore_block,
&ignore_blocks](const BB* entry) {
DepthFirstTraversal(
entry, succ_func, mark_visited, ignore_block, ignore_blocks);
&ignore_blocks](const BB* entry) {
DepthFirstTraversal(entry, succ_func, mark_visited, ignore_block,
ignore_blocks);
};
std::vector<BB*> result;
@ -283,15 +286,13 @@ std::vector<BB*> CFA<BB>::TraversalRoots(
return result;
}
template<class BB>
template <class BB>
void CFA<BB>::ComputeAugmentedCFG(
std::vector<BB*>& ordered_blocks,
BB* pseudo_entry_block, BB* pseudo_exit_block,
std::vector<BB*>& ordered_blocks, BB* pseudo_entry_block,
BB* pseudo_exit_block,
std::unordered_map<const BB*, std::vector<BB*>>* augmented_successors_map,
std::unordered_map<const BB*, std::vector<BB*>>* augmented_predecessors_map,
get_blocks_func succ_func,
get_blocks_func pred_func) {
get_blocks_func succ_func, get_blocks_func pred_func) {
// Compute the successors of the pseudo-entry block, and
// the predecessors of the pseudo exit block.
auto sources = TraversalRoots(ordered_blocks, succ_func, pred_func);
@ -308,7 +309,7 @@ void CFA<BB>::ComputeAugmentedCFG(
// constraint when A is a loop header that points to itself as its
// own continue target, and B is the latch block for the loop.
std::vector<BB*> reversed_blocks(ordered_blocks.rbegin(),
ordered_blocks.rend());
ordered_blocks.rend());
auto sinks = TraversalRoots(reversed_blocks, pred_func, succ_func);
// Wire up the pseudo entry block.
@ -332,6 +333,6 @@ void CFA<BB>::ComputeAugmentedCFG(
}
};
} // namespace spvtools
} // namespace spvtools
#endif // SPVTOOLS_CFA_H_

View File

@ -38,9 +38,9 @@ struct MarkvCodecOptions {
// |bits| is a textual representation of the MARK-V bit sequence used to encode
// the instruction (char '0' for 0, char '1' for 1).
// |comment| contains all logs generated while processing the instruction.
using MarkvDebugConsumer = std::function<bool(
const std::vector<uint32_t>& words, const std::string& bits,
const std::string& comment)>;
using MarkvDebugConsumer =
std::function<bool(const std::vector<uint32_t>& words,
const std::string& bits, const std::string& comment)>;
// Logging callback. Called often (if decoder reads a single bit, the log
// consumer will receive 1 character string with that bit).
@ -54,26 +54,20 @@ using MarkvLogConsumer = std::function<void(const std::string& snippet)>;
// Encodes the given SPIR-V binary to MARK-V binary.
// |log_consumer| is optional (pass MarkvLogConsumer() to disable).
// |debug_consumer| is optional (pass MarkvDebugConsumer() to disable).
spv_result_t SpirvToMarkv(spv_const_context context,
const std::vector<uint32_t>& spirv,
const MarkvCodecOptions& options,
const MarkvModel& markv_model,
MessageConsumer message_consumer,
MarkvLogConsumer log_consumer,
MarkvDebugConsumer debug_consumer,
std::vector<uint8_t>* markv);
spv_result_t SpirvToMarkv(
spv_const_context context, const std::vector<uint32_t>& spirv,
const MarkvCodecOptions& options, const MarkvModel& markv_model,
MessageConsumer message_consumer, MarkvLogConsumer log_consumer,
MarkvDebugConsumer debug_consumer, std::vector<uint8_t>* markv);
// Decodes a SPIR-V binary from the given MARK-V binary.
// |log_consumer| is optional (pass MarkvLogConsumer() to disable).
// |debug_consumer| is optional (pass MarkvDebugConsumer() to disable).
spv_result_t MarkvToSpirv(spv_const_context context,
const std::vector<uint8_t>& markv,
const MarkvCodecOptions& options,
const MarkvModel& markv_model,
MessageConsumer message_consumer,
MarkvLogConsumer log_consumer,
MarkvDebugConsumer debug_consumer,
std::vector<uint32_t>* spirv);
spv_result_t MarkvToSpirv(
spv_const_context context, const std::vector<uint8_t>& markv,
const MarkvCodecOptions& options, const MarkvModel& markv_model,
MessageConsumer message_consumer, MarkvLogConsumer log_consumer,
MarkvDebugConsumer debug_consumer, std::vector<uint32_t>* spirv);
} // namespace spvtools

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,8 @@
#include <unordered_set>
#include <vector>
#include "spirv/1.2/spirv.h"
#include "spirv-tools/libspirv.h"
#include "spirv/1.2/spirv.h"
#include "util/huffman_codec.h"
namespace spvtools {
@ -30,14 +30,17 @@ namespace spvtools {
// codecs used by the compression algorithm.
class MarkvModel {
public:
MarkvModel() : operand_chunk_lengths_(
static_cast<size_t>(SPV_OPERAND_TYPE_NUM_OPERAND_TYPES), 0) {}
MarkvModel()
: operand_chunk_lengths_(
static_cast<size_t>(SPV_OPERAND_TYPE_NUM_OPERAND_TYPES), 0) {}
uint32_t model_type() const { return model_type_; }
uint32_t model_version() const { return model_version_; }
uint32_t opcode_chunk_length() const { return opcode_chunk_length_; }
uint32_t num_operands_chunk_length() const { return num_operands_chunk_length_; }
uint32_t num_operands_chunk_length() const {
return num_operands_chunk_length_;
}
uint32_t mtf_rank_chunk_length() const { return mtf_rank_chunk_length_; }
uint32_t u64_chunk_length() const { return u64_chunk_length_; }
@ -46,8 +49,8 @@ class MarkvModel {
// Returns a codec for common opcode_and_num_operands words for the given
// previous opcode. May return nullptr if the codec doesn't exist.
const spvutils::HuffmanCodec<uint64_t>* GetOpcodeAndNumOperandsMarkovHuffmanCodec(
uint32_t prev_opcode) const {
const spvutils::HuffmanCodec<uint64_t>*
GetOpcodeAndNumOperandsMarkovHuffmanCodec(uint32_t prev_opcode) const {
if (prev_opcode == SpvOpNop)
return opcode_and_num_operands_huffman_codec_.get();
@ -65,8 +68,7 @@ class MarkvModel {
uint32_t opcode, uint32_t operand_index) const {
const auto it = non_id_word_huffman_codecs_.find(
std::pair<uint32_t, uint32_t>(opcode, operand_index));
if (it == non_id_word_huffman_codecs_.end())
return nullptr;
if (it == non_id_word_huffman_codecs_.end()) return nullptr;
return it->second.get();
}
@ -77,8 +79,7 @@ class MarkvModel {
uint32_t opcode, uint32_t operand_index) const {
const auto it = id_descriptor_huffman_codecs_.find(
std::pair<uint32_t, uint32_t>(opcode, operand_index));
if (it == id_descriptor_huffman_codecs_.end())
return nullptr;
if (it == id_descriptor_huffman_codecs_.end()) return nullptr;
return it->second.get();
}
@ -88,8 +89,7 @@ class MarkvModel {
const spvutils::HuffmanCodec<std::string>* GetLiteralStringHuffmanCodec(
uint32_t opcode) const {
const auto it = literal_string_huffman_codecs_.find(opcode);
if (it == literal_string_huffman_codecs_.end())
return nullptr;
if (it == literal_string_huffman_codecs_.end()) return nullptr;
return it->second.get();
}
@ -106,9 +106,7 @@ class MarkvModel {
}
// Sets model type.
void SetModelType(uint32_t in_model_type) {
model_type_ = in_model_type;
}
void SetModelType(uint32_t in_model_type) { model_type_ = in_model_type; }
// Sets model version.
void SetModelVersion(uint32_t in_model_version) {
@ -137,12 +135,14 @@ class MarkvModel {
// Huffman codecs for non-id single-word operand values.
// The map key is pair <opcode, operand_index>.
std::map<std::pair<uint32_t, uint32_t>,
std::unique_ptr<spvutils::HuffmanCodec<uint64_t>>> non_id_word_huffman_codecs_;
std::unique_ptr<spvutils::HuffmanCodec<uint64_t>>>
non_id_word_huffman_codecs_;
// Huffman codecs for id descriptors. The map key is pair
// <opcode, operand_index>.
std::map<std::pair<uint32_t, uint32_t>,
std::unique_ptr<spvutils::HuffmanCodec<uint64_t>>> id_descriptor_huffman_codecs_;
std::unique_ptr<spvutils::HuffmanCodec<uint64_t>>>
id_descriptor_huffman_codecs_;
// Set of all descriptors which have a coding scheme in any of
// id_descriptor_huffman_codecs_.
@ -160,7 +160,7 @@ class MarkvModel {
std::vector<uint32_t> operand_chunk_lengths_;
uint32_t opcode_chunk_length_ = 7;
uint32_t num_operands_chunk_length_ = 3;
uint32_t num_operands_chunk_length_ = 3;
uint32_t mtf_rank_chunk_length_ = 5;
uint32_t u64_chunk_length_ = 8;

View File

@ -23,8 +23,7 @@
namespace libspirv {
std::string GetExtensionString(const spv_parsed_instruction_t* inst) {
if (inst->opcode != SpvOpExtension)
return "ERROR_not_op_extension";
if (inst->opcode != SpvOpExtension) return "ERROR_not_op_extension";
assert(inst->num_operands == 1);
@ -37,9 +36,8 @@ std::string GetExtensionString(const spv_parsed_instruction_t* inst) {
std::string ExtensionSetToString(const ExtensionSet& extensions) {
std::stringstream ss;
extensions.ForEach([&ss](Extension ext) {
ss << ExtensionToString(ext) << " ";
});
extensions.ForEach(
[&ss](Extension ext) { ss << ExtensionToString(ext) << " "; });
return ss.str();
}

View File

@ -40,15 +40,14 @@ uint32_t HashU32Array(const std::vector<uint32_t>& words) {
uint32_t IdDescriptorCollection::ProcessInstruction(
const spv_parsed_instruction_t& inst) {
if (!inst.result_id)
return 0;
if (!inst.result_id) return 0;
assert(words_.empty());
words_.push_back(inst.words[0]);
for (size_t operand_index = 0; operand_index < inst.num_operands;
++operand_index) {
const auto &operand = inst.operands[operand_index];
const auto& operand = inst.operands[operand_index];
if (spvIsIdType(operand.type)) {
const uint32_t id = inst.words[operand.offset];
const auto it = id_to_descriptor_.find(id);

View File

@ -28,9 +28,7 @@ namespace libspirv {
// were substituted with previously computed descriptors.
class IdDescriptorCollection {
public:
IdDescriptorCollection() {
words_.reserve(16);
}
IdDescriptorCollection() { words_.reserve(16); }
// Computes descriptor for the result id of the given instruction and
// registers it in id_to_descriptor_. Returns the computed descriptor.
@ -41,8 +39,7 @@ class IdDescriptorCollection {
// Returns a previously computed descriptor id.
uint32_t GetDescriptor(uint32_t id) const {
const auto it = id_to_descriptor_.find(id);
if (it == id_to_descriptor_.end())
return 0;
if (it == id_to_descriptor_.end()) return 0;
return it->second;
}
@ -56,4 +53,3 @@ class IdDescriptorCollection {
} // namespace libspirv
#endif // LIBSPIRV_ID_DESCRIPTOR_H_

View File

@ -497,7 +497,7 @@ static spv_result_t GetImportExportPairs(
// Ignore if the targeted symbol is a built-in
bool is_built_in = false;
for (const auto& id_decoration :
decoration_manager.GetDecorationsFor(id, false)) {
decoration_manager.GetDecorationsFor(id, false)) {
if (id_decoration->GetSingleWordInOperand(1u) == SpvDecorationBuiltIn) {
is_built_in = true;
break;

View File

@ -14,8 +14,8 @@
#include "name_mapper.h"
#include <cassert>
#include <algorithm>
#include <cassert>
#include <iterator>
#include <sstream>
#include <string>
@ -234,26 +234,30 @@ spv_result_t FriendlyNameMapper::ParseInstruction(
}
} break;
case SpvOpTypeVector:
SaveName(result_id, std::string("v") + to_string(inst.words[3]) +
NameForId(inst.words[2]));
SaveName(result_id,
std::string("v") + to_string(inst.words[3]) +
NameForId(inst.words[2]));
break;
case SpvOpTypeMatrix:
SaveName(result_id, std::string("mat") + to_string(inst.words[3]) +
NameForId(inst.words[2]));
SaveName(result_id,
std::string("mat") + to_string(inst.words[3]) +
NameForId(inst.words[2]));
break;
case SpvOpTypeArray:
SaveName(result_id, std::string("_arr_") + NameForId(inst.words[2]) +
"_" + NameForId(inst.words[3]));
SaveName(result_id,
std::string("_arr_") + NameForId(inst.words[2]) + "_" +
NameForId(inst.words[3]));
break;
case SpvOpTypeRuntimeArray:
SaveName(result_id,
std::string("_runtimearr_") + NameForId(inst.words[2]));
break;
case SpvOpTypePointer:
SaveName(result_id, std::string("_ptr_") +
NameForEnumOperand(SPV_OPERAND_TYPE_STORAGE_CLASS,
inst.words[2]) +
"_" + NameForId(inst.words[3]));
SaveName(result_id,
std::string("_ptr_") +
NameForEnumOperand(SPV_OPERAND_TYPE_STORAGE_CLASS,
inst.words[2]) +
"_" + NameForId(inst.words[3]));
break;
case SpvOpTypePipe:
SaveName(result_id,

View File

@ -20,8 +20,8 @@
#include <unordered_map>
#include <unordered_set>
#include "spirv-tools/libspirv.h"
#include "assembly_grammar.h"
#include "spirv-tools/libspirv.h"
namespace libspirv {
@ -41,7 +41,8 @@ NameMapper GetTrivialNameMapper();
// - If an Id has a debug name (via OpName), then that will be used when
// possible.
// - Well known scalar types map to friendly names. For example,
// OpTypeVoid should be %void. Scalar types map to their names in OpenCL when
// OpTypeVoid should be %void. Scalar types map to their names in OpenCL
// when
// there is a correspondence, and otherwise as follows:
// - unsigned integer type of n bits map to "u" followed by n
// - signed integer type of n bits map to "i" followed by n

View File

@ -147,7 +147,7 @@ spv_result_t spvOpcodeTableValueLookup(const spv_opcode_table table,
return lhs.opcode < rhs.opcode;
};
auto it = std::lower_bound(beg, end, value, comp);
if (it!=end && it->opcode == opcode) {
if (it != end && it->opcode == opcode) {
*pEntry = it;
return SPV_SUCCESS;
}
@ -177,13 +177,14 @@ const char* spvOpcodeString(const SpvOp opcode) {
// previous ones.
const auto beg = kOpcodeTableEntries_1_2;
const auto end = kOpcodeTableEntries_1_2 + ARRAY_SIZE(kOpcodeTableEntries_1_2);
const auto end =
kOpcodeTableEntries_1_2 + ARRAY_SIZE(kOpcodeTableEntries_1_2);
spv_opcode_desc_t value{"", opcode, 0, nullptr, 0, {}, 0, 0};
auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
return lhs.opcode < rhs.opcode;
};
auto it = std::lower_bound(beg, end, value, comp);
if (it!=end && it->opcode == opcode) {
if (it != end && it->opcode == opcode) {
return it->name;
}

View File

@ -36,29 +36,25 @@ const uint32_t kLoopMergeMergeBlockIdInIdx = 0;
} // namespace anonymous
bool AggressiveDCEPass::IsVarOfStorage(uint32_t varId,
uint32_t storageClass) {
bool AggressiveDCEPass::IsVarOfStorage(uint32_t varId, uint32_t storageClass) {
const ir::Instruction* varInst = get_def_use_mgr()->GetDef(varId);
const SpvOp op = varInst->opcode();
if (op != SpvOpVariable)
return false;
if (op != SpvOpVariable) return false;
const uint32_t varTypeId = varInst->type_id();
const ir::Instruction* varTypeInst = get_def_use_mgr()->GetDef(varTypeId);
if (varTypeInst->opcode() != SpvOpTypePointer)
return false;
if (varTypeInst->opcode() != SpvOpTypePointer) return false;
return varTypeInst->GetSingleWordInOperand(kTypePointerStorageClassInIdx) ==
storageClass;
storageClass;
}
bool AggressiveDCEPass::IsLocalVar(uint32_t varId) {
return IsVarOfStorage(varId, SpvStorageClassFunction) ||
(IsVarOfStorage(varId, SpvStorageClassPrivate) && private_like_local_);
return IsVarOfStorage(varId, SpvStorageClassFunction) ||
(IsVarOfStorage(varId, SpvStorageClassPrivate) && private_like_local_);
}
void AggressiveDCEPass::AddStores(uint32_t ptrId) {
const analysis::UseList* uses = get_def_use_mgr()->GetUses(ptrId);
if (uses == nullptr)
return;
if (uses == nullptr) return;
for (const auto u : *uses) {
const SpvOp op = u.inst->opcode();
switch (op) {
@ -72,8 +68,7 @@ void AggressiveDCEPass::AddStores(uint32_t ptrId) {
// If default, assume it stores eg frexp, modf, function call
case SpvOpStore:
default: {
if (!IsLive(u.inst))
AddToWorklist(u.inst);
if (!IsLive(u.inst)) AddToWorklist(u.inst);
} break;
}
}
@ -88,17 +83,16 @@ bool AggressiveDCEPass::IsCombinatorExt(ir::Instruction* inst) const {
if (inst->GetSingleWordInOperand(kExtInstSetIdInIndx) == glsl_std_450_id_) {
uint32_t op = inst->GetSingleWordInOperand(kExtInstInstructionInIndx);
return combinator_ops_glsl_std_450_.find(op) !=
combinator_ops_glsl_std_450_.end();
}
else
combinator_ops_glsl_std_450_.end();
} else
return false;
}
bool AggressiveDCEPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : get_module()->extensions()) {
const char* extName = reinterpret_cast<const char*>(
&ei.GetInOperand(0).words[0]);
const char* extName =
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
return false;
}
@ -117,11 +111,9 @@ bool AggressiveDCEPass::KillInstIfTargetDead(ir::Instruction* inst) {
void AggressiveDCEPass::ProcessLoad(uint32_t varId) {
// Only process locals
if (!IsLocalVar(varId))
return;
if (!IsLocalVar(varId)) return;
// Return if already processed
if (live_local_vars_.find(varId) != live_local_vars_.end())
return;
if (live_local_vars_.find(varId) != live_local_vars_.end()) return;
// Mark all stores to varId as live
AddStores(varId);
// Cache varId as processed
@ -129,20 +121,17 @@ void AggressiveDCEPass::ProcessLoad(uint32_t varId) {
}
bool AggressiveDCEPass::IsStructuredIfHeader(ir::BasicBlock* bp,
ir::Instruction** mergeInst, ir::Instruction** branchInst,
uint32_t* mergeBlockId) {
ir::Instruction** mergeInst,
ir::Instruction** branchInst,
uint32_t* mergeBlockId) {
auto ii = bp->end();
--ii;
if (ii->opcode() != SpvOpBranchConditional)
return false;
if (ii == bp->begin())
return false;
if (ii->opcode() != SpvOpBranchConditional) return false;
if (ii == bp->begin()) return false;
if (branchInst != nullptr) *branchInst = &*ii;
--ii;
if (ii->opcode() != SpvOpSelectionMerge)
return false;
if (mergeInst != nullptr)
*mergeInst = &*ii;
if (ii->opcode() != SpvOpSelectionMerge) return false;
if (mergeInst != nullptr) *mergeInst = &*ii;
if (mergeBlockId != nullptr)
*mergeBlockId =
ii->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx);
@ -150,7 +139,7 @@ bool AggressiveDCEPass::IsStructuredIfHeader(ir::BasicBlock* bp,
}
void AggressiveDCEPass::ComputeBlock2HeaderMaps(
std::list<ir::BasicBlock*>& structuredOrder) {
std::list<ir::BasicBlock*>& structuredOrder) {
block2headerMerge_.clear();
block2headerBranch_.clear();
std::stack<ir::Instruction*> currentMergeInst;
@ -180,16 +169,15 @@ void AggressiveDCEPass::ComputeBlock2HeaderMaps(
void AggressiveDCEPass::ComputeInst2BlockMap(ir::Function* func) {
for (auto& blk : *func) {
blk.ForEachInst([&blk,this](ir::Instruction* ip) {
inst2block_[ip] = &blk;
});
blk.ForEachInst(
[&blk, this](ir::Instruction* ip) { inst2block_[ip] = &blk; });
}
}
void AggressiveDCEPass::AddBranch(uint32_t labelId, ir::BasicBlock* bp) {
std::unique_ptr<ir::Instruction> newBranch(
new ir::Instruction(SpvOpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}}}));
std::unique_ptr<ir::Instruction> newBranch(new ir::Instruction(
SpvOpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}}}));
get_def_use_mgr()->AnalyzeInstDefUse(&*newBranch);
bp->AddInstruction(std::move(newBranch));
}
@ -209,7 +197,7 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
func_is_entry_point_ = false;
private_stores_.clear();
// Stacks to keep track of when we are inside an if-construct. When not
// immediately inside an in-construct, we must assume all branches are live.
// immediately inside an in-construct, we must assume all branches are live.
std::stack<bool> assume_branches_live;
std::stack<uint32_t> currentMergeBlockId;
// Push sentinel values on stack for when outside of any control flow.
@ -225,7 +213,7 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
switch (op) {
case SpvOpStore: {
uint32_t varId;
(void) GetPtr(&*ii, &varId);
(void)GetPtr(&*ii, &varId);
// Mark stores as live if their variable is not function scope
// and is not private scope. Remember private stores for possible
// later inclusion
@ -236,8 +224,7 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
} break;
case SpvOpExtInst: {
// eg. GLSL frexp, modf
if (!IsCombinatorExt(&*ii))
AddToWorklist(&*ii);
if (!IsCombinatorExt(&*ii)) AddToWorklist(&*ii);
} break;
case SpvOpLoopMerge: {
// Assume loops live (for now)
@ -254,22 +241,18 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
assume_branches_live.push(!is_structured_if);
currentMergeBlockId.push(
ii->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx));
if (!is_structured_if)
AddToWorklist(&*ii);
if (!is_structured_if) AddToWorklist(&*ii);
} break;
case SpvOpBranch:
case SpvOpBranchConditional: {
if (assume_branches_live.top())
AddToWorklist(&*ii);
if (assume_branches_live.top()) AddToWorklist(&*ii);
} break;
default: {
// Function calls, atomics, function params, function returns, etc.
// TODO(greg-lunarg): function calls live only if write to non-local
if (!IsCombinator(op))
AddToWorklist(&*ii);
if (!IsCombinator(op)) AddToWorklist(&*ii);
// Remember function calls
if (op == SpvOpFunctionCall)
call_in_func_ = true;
if (op == SpvOpFunctionCall) call_in_func_ = true;
} break;
}
}
@ -287,23 +270,20 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
private_like_local_ = func_is_entry_point_ && !call_in_func_;
// If privates are not like local, add their stores to worklist
if (!private_like_local_)
for (auto& ps : private_stores_)
AddToWorklist(ps);
for (auto& ps : private_stores_) AddToWorklist(ps);
// Add OpGroupDecorates to worklist because they are a pain to remove
// ids from.
// TODO(greg-lunarg): Handle dead ids in OpGroupDecorate
for (auto& ai : get_module()->annotations()) {
if (ai.opcode() == SpvOpGroupDecorate)
AddToWorklist(&ai);
if (ai.opcode() == SpvOpGroupDecorate) AddToWorklist(&ai);
}
// Perform closure on live instruction set.
// Perform closure on live instruction set.
while (!worklist_.empty()) {
ir::Instruction* liveInst = worklist_.front();
// Add all operand instructions if not already live
liveInst->ForEachInId([this](const uint32_t* iid) {
ir::Instruction* inInst = get_def_use_mgr()->GetDef(*iid);
if (!IsLive(inInst))
AddToWorklist(inInst);
if (!IsLive(inInst)) AddToWorklist(inInst);
});
// If in a structured if construct, add the controlling conditional branch
// and its merge. Any containing if construct is marked live when the
@ -317,7 +297,7 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
// If local load, add all variable's stores if variable not already live
if (liveInst->opcode() == SpvOpLoad) {
uint32_t varId;
(void) GetPtr(liveInst, &varId);
(void)GetPtr(liveInst, &varId);
ProcessLoad(varId);
}
// If function call, treat as if it loads from all pointer arguments
@ -326,7 +306,7 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
// Skip non-ptr args
if (!IsPtr(*iid)) return;
uint32_t varId;
(void) GetPtr(*iid, &varId);
(void)GetPtr(*iid, &varId);
ProcessLoad(varId);
});
}
@ -340,8 +320,7 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
// at the end of an if-header, which indicate a dead if.
for (auto bi = structuredOrder.begin(); bi != structuredOrder.end(); ++bi) {
for (auto ii = (*bi)->begin(); ii != (*bi)->end(); ++ii) {
if (IsLive(&*ii))
continue;
if (IsLive(&*ii)) continue;
if (IsBranch(ii->opcode()) &&
!IsStructuredIfHeader(*bi, nullptr, nullptr, nullptr))
continue;
@ -352,27 +331,23 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
// This must be done before killing the instructions, otherwise there are
// dead objects in the def/use database.
for (auto& di : get_module()->debugs2()) {
if (di.opcode() != SpvOpName)
continue;
if (KillInstIfTargetDead(&di))
modified = true;
if (di.opcode() != SpvOpName) continue;
if (KillInstIfTargetDead(&di)) modified = true;
}
for (auto& ai : get_module()->annotations()) {
if (ai.opcode() != SpvOpDecorate && ai.opcode() != SpvOpDecorateId)
continue;
if (KillInstIfTargetDead(&ai))
modified = true;
if (KillInstIfTargetDead(&ai)) modified = true;
}
// Kill dead instructions and remember dead blocks
for (auto bi = structuredOrder.begin(); bi != structuredOrder.end();) {
uint32_t mergeBlockId = 0;
for (auto ii = (*bi)->begin(); ii != (*bi)->end(); ++ii) {
if (dead_insts_.find(&*ii) == dead_insts_.end())
continue;
if (dead_insts_.find(&*ii) == dead_insts_.end()) continue;
// If dead instruction is selection merge, remember merge block
// for new branch at end of block
if (ii->opcode() == SpvOpSelectionMerge)
mergeBlockId =
mergeBlockId =
ii->GetSingleWordInOperand(kSelectionMergeMergeBlockIdInIdx);
context()->KillInst(&*ii);
modified = true;
@ -384,8 +359,7 @@ bool AggressiveDCEPass::AggressiveDCE(ir::Function* func) {
AddBranch(mergeBlockId, *bi);
for (++bi; (*bi)->id() != mergeBlockId; ++bi) {
}
}
else {
} else {
++bi;
}
}
@ -412,7 +386,7 @@ void AggressiveDCEPass::Initialize(ir::IRContext* c) {
}
Pass::Status AggressiveDCEPass::ProcessImpl() {
// Current functionality assumes shader capability
// Current functionality assumes shader capability
// TODO(greg-lunarg): Handle additional capabilities
if (!get_module()->HasCapability(SpvCapabilityShader))
return Status::SuccessWithoutChange;
@ -421,15 +395,12 @@ Pass::Status AggressiveDCEPass::ProcessImpl() {
if (get_module()->HasCapability(SpvCapabilityAddresses))
return Status::SuccessWithoutChange;
// If any extensions in the module are not explicitly supported,
// return unmodified.
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
// return unmodified.
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Initialize combinator whitelists
InitCombinatorSets();
// Process all entry point functions
ProcessFunction pfn = [this](ir::Function* fp) {
return AggressiveDCE(fp);
};
ProcessFunction pfn = [this](ir::Function* fp) { return AggressiveDCE(fp); };
bool modified = ProcessEntryPointCallTree(pfn, get_module());
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
@ -443,258 +414,246 @@ Pass::Status AggressiveDCEPass::Process(ir::IRContext* c) {
void AggressiveDCEPass::InitCombinatorSets() {
combinator_ops_shader_ = {
SpvOpNop,
SpvOpUndef,
SpvOpVariable,
SpvOpImageTexelPointer,
SpvOpLoad,
SpvOpAccessChain,
SpvOpInBoundsAccessChain,
SpvOpArrayLength,
SpvOpVectorExtractDynamic,
SpvOpVectorInsertDynamic,
SpvOpVectorShuffle,
SpvOpCompositeConstruct,
SpvOpCompositeExtract,
SpvOpCompositeInsert,
SpvOpCopyObject,
SpvOpTranspose,
SpvOpSampledImage,
SpvOpImageSampleImplicitLod,
SpvOpImageSampleExplicitLod,
SpvOpImageSampleDrefImplicitLod,
SpvOpImageSampleDrefExplicitLod,
SpvOpImageSampleProjImplicitLod,
SpvOpImageSampleProjExplicitLod,
SpvOpImageSampleProjDrefImplicitLod,
SpvOpImageSampleProjDrefExplicitLod,
SpvOpImageFetch,
SpvOpImageGather,
SpvOpImageDrefGather,
SpvOpImageRead,
SpvOpImage,
SpvOpConvertFToU,
SpvOpConvertFToS,
SpvOpConvertSToF,
SpvOpConvertUToF,
SpvOpUConvert,
SpvOpSConvert,
SpvOpFConvert,
SpvOpQuantizeToF16,
SpvOpBitcast,
SpvOpSNegate,
SpvOpFNegate,
SpvOpIAdd,
SpvOpFAdd,
SpvOpISub,
SpvOpFSub,
SpvOpIMul,
SpvOpFMul,
SpvOpUDiv,
SpvOpSDiv,
SpvOpFDiv,
SpvOpUMod,
SpvOpSRem,
SpvOpSMod,
SpvOpFRem,
SpvOpFMod,
SpvOpVectorTimesScalar,
SpvOpMatrixTimesScalar,
SpvOpVectorTimesMatrix,
SpvOpMatrixTimesVector,
SpvOpMatrixTimesMatrix,
SpvOpOuterProduct,
SpvOpDot,
SpvOpIAddCarry,
SpvOpISubBorrow,
SpvOpUMulExtended,
SpvOpSMulExtended,
SpvOpAny,
SpvOpAll,
SpvOpIsNan,
SpvOpIsInf,
SpvOpLogicalEqual,
SpvOpLogicalNotEqual,
SpvOpLogicalOr,
SpvOpLogicalAnd,
SpvOpLogicalNot,
SpvOpSelect,
SpvOpIEqual,
SpvOpINotEqual,
SpvOpUGreaterThan,
SpvOpSGreaterThan,
SpvOpUGreaterThanEqual,
SpvOpSGreaterThanEqual,
SpvOpULessThan,
SpvOpSLessThan,
SpvOpULessThanEqual,
SpvOpSLessThanEqual,
SpvOpFOrdEqual,
SpvOpFUnordEqual,
SpvOpFOrdNotEqual,
SpvOpFUnordNotEqual,
SpvOpFOrdLessThan,
SpvOpFUnordLessThan,
SpvOpFOrdGreaterThan,
SpvOpFUnordGreaterThan,
SpvOpFOrdLessThanEqual,
SpvOpFUnordLessThanEqual,
SpvOpFOrdGreaterThanEqual,
SpvOpFUnordGreaterThanEqual,
SpvOpShiftRightLogical,
SpvOpShiftRightArithmetic,
SpvOpShiftLeftLogical,
SpvOpBitwiseOr,
SpvOpBitwiseXor,
SpvOpBitwiseAnd,
SpvOpNot,
SpvOpBitFieldInsert,
SpvOpBitFieldSExtract,
SpvOpBitFieldUExtract,
SpvOpBitReverse,
SpvOpBitCount,
SpvOpDPdx,
SpvOpDPdy,
SpvOpFwidth,
SpvOpDPdxFine,
SpvOpDPdyFine,
SpvOpFwidthFine,
SpvOpDPdxCoarse,
SpvOpDPdyCoarse,
SpvOpFwidthCoarse,
SpvOpPhi,
SpvOpImageSparseSampleImplicitLod,
SpvOpImageSparseSampleExplicitLod,
SpvOpImageSparseSampleDrefImplicitLod,
SpvOpImageSparseSampleDrefExplicitLod,
SpvOpImageSparseSampleProjImplicitLod,
SpvOpImageSparseSampleProjExplicitLod,
SpvOpImageSparseSampleProjDrefImplicitLod,
SpvOpImageSparseSampleProjDrefExplicitLod,
SpvOpImageSparseFetch,
SpvOpImageSparseGather,
SpvOpImageSparseDrefGather,
SpvOpImageSparseTexelsResident,
SpvOpImageSparseRead,
SpvOpSizeOf
// TODO(dneto): Add instructions enabled by ImageQuery
SpvOpNop,
SpvOpUndef,
SpvOpVariable,
SpvOpImageTexelPointer,
SpvOpLoad,
SpvOpAccessChain,
SpvOpInBoundsAccessChain,
SpvOpArrayLength,
SpvOpVectorExtractDynamic,
SpvOpVectorInsertDynamic,
SpvOpVectorShuffle,
SpvOpCompositeConstruct,
SpvOpCompositeExtract,
SpvOpCompositeInsert,
SpvOpCopyObject,
SpvOpTranspose,
SpvOpSampledImage,
SpvOpImageSampleImplicitLod,
SpvOpImageSampleExplicitLod,
SpvOpImageSampleDrefImplicitLod,
SpvOpImageSampleDrefExplicitLod,
SpvOpImageSampleProjImplicitLod,
SpvOpImageSampleProjExplicitLod,
SpvOpImageSampleProjDrefImplicitLod,
SpvOpImageSampleProjDrefExplicitLod,
SpvOpImageFetch,
SpvOpImageGather,
SpvOpImageDrefGather,
SpvOpImageRead,
SpvOpImage,
SpvOpConvertFToU,
SpvOpConvertFToS,
SpvOpConvertSToF,
SpvOpConvertUToF,
SpvOpUConvert,
SpvOpSConvert,
SpvOpFConvert,
SpvOpQuantizeToF16,
SpvOpBitcast,
SpvOpSNegate,
SpvOpFNegate,
SpvOpIAdd,
SpvOpFAdd,
SpvOpISub,
SpvOpFSub,
SpvOpIMul,
SpvOpFMul,
SpvOpUDiv,
SpvOpSDiv,
SpvOpFDiv,
SpvOpUMod,
SpvOpSRem,
SpvOpSMod,
SpvOpFRem,
SpvOpFMod,
SpvOpVectorTimesScalar,
SpvOpMatrixTimesScalar,
SpvOpVectorTimesMatrix,
SpvOpMatrixTimesVector,
SpvOpMatrixTimesMatrix,
SpvOpOuterProduct,
SpvOpDot,
SpvOpIAddCarry,
SpvOpISubBorrow,
SpvOpUMulExtended,
SpvOpSMulExtended,
SpvOpAny,
SpvOpAll,
SpvOpIsNan,
SpvOpIsInf,
SpvOpLogicalEqual,
SpvOpLogicalNotEqual,
SpvOpLogicalOr,
SpvOpLogicalAnd,
SpvOpLogicalNot,
SpvOpSelect,
SpvOpIEqual,
SpvOpINotEqual,
SpvOpUGreaterThan,
SpvOpSGreaterThan,
SpvOpUGreaterThanEqual,
SpvOpSGreaterThanEqual,
SpvOpULessThan,
SpvOpSLessThan,
SpvOpULessThanEqual,
SpvOpSLessThanEqual,
SpvOpFOrdEqual,
SpvOpFUnordEqual,
SpvOpFOrdNotEqual,
SpvOpFUnordNotEqual,
SpvOpFOrdLessThan,
SpvOpFUnordLessThan,
SpvOpFOrdGreaterThan,
SpvOpFUnordGreaterThan,
SpvOpFOrdLessThanEqual,
SpvOpFUnordLessThanEqual,
SpvOpFOrdGreaterThanEqual,
SpvOpFUnordGreaterThanEqual,
SpvOpShiftRightLogical,
SpvOpShiftRightArithmetic,
SpvOpShiftLeftLogical,
SpvOpBitwiseOr,
SpvOpBitwiseXor,
SpvOpBitwiseAnd,
SpvOpNot,
SpvOpBitFieldInsert,
SpvOpBitFieldSExtract,
SpvOpBitFieldUExtract,
SpvOpBitReverse,
SpvOpBitCount,
SpvOpDPdx,
SpvOpDPdy,
SpvOpFwidth,
SpvOpDPdxFine,
SpvOpDPdyFine,
SpvOpFwidthFine,
SpvOpDPdxCoarse,
SpvOpDPdyCoarse,
SpvOpFwidthCoarse,
SpvOpPhi,
SpvOpImageSparseSampleImplicitLod,
SpvOpImageSparseSampleExplicitLod,
SpvOpImageSparseSampleDrefImplicitLod,
SpvOpImageSparseSampleDrefExplicitLod,
SpvOpImageSparseSampleProjImplicitLod,
SpvOpImageSparseSampleProjExplicitLod,
SpvOpImageSparseSampleProjDrefImplicitLod,
SpvOpImageSparseSampleProjDrefExplicitLod,
SpvOpImageSparseFetch,
SpvOpImageSparseGather,
SpvOpImageSparseDrefGather,
SpvOpImageSparseTexelsResident,
SpvOpImageSparseRead,
SpvOpSizeOf
// TODO(dneto): Add instructions enabled by ImageQuery
};
// Find supported extension instruction set ids
glsl_std_450_id_ = get_module()->GetExtInstImportId("GLSL.std.450");
combinator_ops_glsl_std_450_ = {
GLSLstd450Round,
GLSLstd450RoundEven,
GLSLstd450Trunc,
GLSLstd450FAbs,
GLSLstd450SAbs,
GLSLstd450FSign,
GLSLstd450SSign,
GLSLstd450Floor,
GLSLstd450Ceil,
GLSLstd450Fract,
GLSLstd450Radians,
GLSLstd450Degrees,
GLSLstd450Sin,
GLSLstd450Cos,
GLSLstd450Tan,
GLSLstd450Asin,
GLSLstd450Acos,
GLSLstd450Atan,
GLSLstd450Sinh,
GLSLstd450Cosh,
GLSLstd450Tanh,
GLSLstd450Asinh,
GLSLstd450Acosh,
GLSLstd450Atanh,
GLSLstd450Atan2,
GLSLstd450Pow,
GLSLstd450Exp,
GLSLstd450Log,
GLSLstd450Exp2,
GLSLstd450Log2,
GLSLstd450Sqrt,
GLSLstd450InverseSqrt,
GLSLstd450Determinant,
GLSLstd450MatrixInverse,
GLSLstd450ModfStruct,
GLSLstd450FMin,
GLSLstd450UMin,
GLSLstd450SMin,
GLSLstd450FMax,
GLSLstd450UMax,
GLSLstd450SMax,
GLSLstd450FClamp,
GLSLstd450UClamp,
GLSLstd450SClamp,
GLSLstd450FMix,
GLSLstd450IMix,
GLSLstd450Step,
GLSLstd450SmoothStep,
GLSLstd450Fma,
GLSLstd450FrexpStruct,
GLSLstd450Ldexp,
GLSLstd450PackSnorm4x8,
GLSLstd450PackUnorm4x8,
GLSLstd450PackSnorm2x16,
GLSLstd450PackUnorm2x16,
GLSLstd450PackHalf2x16,
GLSLstd450PackDouble2x32,
GLSLstd450UnpackSnorm2x16,
GLSLstd450UnpackUnorm2x16,
GLSLstd450UnpackHalf2x16,
GLSLstd450UnpackSnorm4x8,
GLSLstd450UnpackUnorm4x8,
GLSLstd450UnpackDouble2x32,
GLSLstd450Length,
GLSLstd450Distance,
GLSLstd450Cross,
GLSLstd450Normalize,
GLSLstd450FaceForward,
GLSLstd450Reflect,
GLSLstd450Refract,
GLSLstd450FindILsb,
GLSLstd450FindSMsb,
GLSLstd450FindUMsb,
GLSLstd450InterpolateAtCentroid,
GLSLstd450InterpolateAtSample,
GLSLstd450InterpolateAtOffset,
GLSLstd450NMin,
GLSLstd450NMax,
GLSLstd450NClamp
};
combinator_ops_glsl_std_450_ = {GLSLstd450Round,
GLSLstd450RoundEven,
GLSLstd450Trunc,
GLSLstd450FAbs,
GLSLstd450SAbs,
GLSLstd450FSign,
GLSLstd450SSign,
GLSLstd450Floor,
GLSLstd450Ceil,
GLSLstd450Fract,
GLSLstd450Radians,
GLSLstd450Degrees,
GLSLstd450Sin,
GLSLstd450Cos,
GLSLstd450Tan,
GLSLstd450Asin,
GLSLstd450Acos,
GLSLstd450Atan,
GLSLstd450Sinh,
GLSLstd450Cosh,
GLSLstd450Tanh,
GLSLstd450Asinh,
GLSLstd450Acosh,
GLSLstd450Atanh,
GLSLstd450Atan2,
GLSLstd450Pow,
GLSLstd450Exp,
GLSLstd450Log,
GLSLstd450Exp2,
GLSLstd450Log2,
GLSLstd450Sqrt,
GLSLstd450InverseSqrt,
GLSLstd450Determinant,
GLSLstd450MatrixInverse,
GLSLstd450ModfStruct,
GLSLstd450FMin,
GLSLstd450UMin,
GLSLstd450SMin,
GLSLstd450FMax,
GLSLstd450UMax,
GLSLstd450SMax,
GLSLstd450FClamp,
GLSLstd450UClamp,
GLSLstd450SClamp,
GLSLstd450FMix,
GLSLstd450IMix,
GLSLstd450Step,
GLSLstd450SmoothStep,
GLSLstd450Fma,
GLSLstd450FrexpStruct,
GLSLstd450Ldexp,
GLSLstd450PackSnorm4x8,
GLSLstd450PackUnorm4x8,
GLSLstd450PackSnorm2x16,
GLSLstd450PackUnorm2x16,
GLSLstd450PackHalf2x16,
GLSLstd450PackDouble2x32,
GLSLstd450UnpackSnorm2x16,
GLSLstd450UnpackUnorm2x16,
GLSLstd450UnpackHalf2x16,
GLSLstd450UnpackSnorm4x8,
GLSLstd450UnpackUnorm4x8,
GLSLstd450UnpackDouble2x32,
GLSLstd450Length,
GLSLstd450Distance,
GLSLstd450Cross,
GLSLstd450Normalize,
GLSLstd450FaceForward,
GLSLstd450Reflect,
GLSLstd450Refract,
GLSLstd450FindILsb,
GLSLstd450FindSMsb,
GLSLstd450FindUMsb,
GLSLstd450InterpolateAtCentroid,
GLSLstd450InterpolateAtSample,
GLSLstd450InterpolateAtOffset,
GLSLstd450NMin,
GLSLstd450NMax,
GLSLstd450NClamp};
}
void AggressiveDCEPass::InitExtensions() {
extensions_whitelist_.clear();
extensions_whitelist_.insert({
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
// SPV_KHR_variable_pointers
// Currently do not support extended pointer expressions
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot", "SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float", "SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote", "SPV_KHR_16bit_storage", "SPV_KHR_device_group",
"SPV_KHR_multiview", "SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2", "SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough", "SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
// SPV_KHR_variable_pointers
// Currently do not support extended pointer expressions
"SPV_AMD_gpu_shader_int16", "SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
});
}
} // namespace opt
} // namespace spvtools

View File

@ -26,20 +26,19 @@
#include "basic_block.h"
#include "def_use_manager.h"
#include "module.h"
#include "mem_pass.h"
#include "module.h"
namespace spvtools {
namespace opt {
// See optimizer.hpp for documentation.
class AggressiveDCEPass : public MemPass {
using cbb_ptr = const ir::BasicBlock*;
public:
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
AggressiveDCEPass();
const char* name() const override { return "eliminate-dead-code-aggressive"; }
@ -102,9 +101,9 @@ class AggressiveDCEPass : public MemPass {
// If |bp| is structured if header block, return true and set |branchInst|
// to the conditional branch and |mergeBlockId| to the merge block.
bool IsStructuredIfHeader(ir::BasicBlock* bp,
ir::Instruction** mergeInst, ir::Instruction** branchInst,
uint32_t* mergeBlockId);
bool IsStructuredIfHeader(ir::BasicBlock* bp, ir::Instruction** mergeInst,
ir::Instruction** branchInst,
uint32_t* mergeBlockId);
// Initialize block2branch_ and block2merge_ using |structuredOrder| to
// order blocks.
@ -120,7 +119,7 @@ class AggressiveDCEPass : public MemPass {
// and block terminating instructions as live. Recursively mark the values
// they use. When complete, delete any non-live instructions. Return true
// if the function has been modified.
//
//
// Note: This function does not delete useless control structures. All
// existing control structures will remain. This can leave not-insignificant
// sequences of ultimately useless code.
@ -160,7 +159,7 @@ class AggressiveDCEPass : public MemPass {
// Map from block's label id to block.
std::unordered_map<uint32_t, ir::BasicBlock*> id2block_;
// Map from block to its structured successor blocks. See
// Map from block to its structured successor blocks. See
// ComputeStructuredSuccessors() for definition.
std::unordered_map<const ir::BasicBlock*, std::vector<ir::BasicBlock*>>
block2structured_succs_;
@ -200,4 +199,3 @@ class AggressiveDCEPass : public MemPass {
} // namespace spvtools
#endif // LIBSPIRV_OPT_AGGRESSIVE_DCE_PASS_H_

View File

@ -16,8 +16,8 @@
#include "block_merge_pass.h"
#include "iterator.h"
#include "ir_context.h"
#include "iterator.h"
namespace spvtools {
namespace opt {
@ -27,10 +27,8 @@ bool BlockMergePass::HasMultipleRefs(uint32_t labId) {
int rcnt = 0;
for (const auto u : *uses) {
// Don't count OpName
if (u.inst->opcode() == SpvOpName)
continue;
if (rcnt == 1)
return true;
if (u.inst->opcode() == SpvOpName) continue;
if (rcnt == 1) return true;
++rcnt;
}
return false;
@ -52,7 +50,7 @@ void BlockMergePass::KillInstAndName(ir::Instruction* inst) {
bool BlockMergePass::MergeBlocks(ir::Function* func) {
bool modified = false;
for (auto bi = func->begin(); bi != func->end(); ) {
for (auto bi = func->begin(); bi != func->end();) {
// Do not merge loop header blocks, at least for now.
if (bi->IsLoopHeader()) {
++bi;
@ -81,14 +79,13 @@ bool BlockMergePass::MergeBlocks(ir::Function* func) {
context()->KillInst(br);
auto sbi = bi;
for (; sbi != func->end(); ++sbi)
if (sbi->id() == labId)
break;
if (sbi->id() == labId) break;
// If bi is sbi's only predecessor, it dominates sbi and thus
// sbi must follow bi in func's ordering.
assert(sbi != func->end());
bi->AddInstructions(&*sbi);
KillInstAndName(sbi->GetLabelInst());
(void) sbi.Erase();
(void)sbi.Erase();
// reprocess block
modified = true;
}
@ -105,8 +102,8 @@ void BlockMergePass::Initialize(ir::IRContext* c) {
bool BlockMergePass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : get_module()->extensions()) {
const char* extName = reinterpret_cast<const char*>(
&ei.GetInOperand(0).words[0]);
const char* extName =
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
return false;
}
@ -115,12 +112,9 @@ bool BlockMergePass::AllExtensionsSupported() const {
Pass::Status BlockMergePass::ProcessImpl() {
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process all entry point functions.
ProcessFunction pfn = [this](ir::Function* fp) {
return MergeBlocks(fp);
};
ProcessFunction pfn = [this](ir::Function* fp) { return MergeBlocks(fp); };
bool modified = ProcessEntryPointCallTree(pfn, get_module());
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
@ -135,31 +129,30 @@ Pass::Status BlockMergePass::Process(ir::IRContext* c) {
void BlockMergePass::InitExtensions() {
extensions_whitelist_.clear();
extensions_whitelist_.insert({
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
"SPV_KHR_variable_pointers",
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
"SPV_KHR_variable_pointers",
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
});
}
} // namespace opt
} // namespace spvtools

View File

@ -26,9 +26,9 @@
#include "basic_block.h"
#include "def_use_manager.h"
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {
@ -68,4 +68,3 @@ class BlockMergePass : public Pass {
} // namespace spvtools
#endif // LIBSPIRV_OPT_BLOCK_MERGE_PASS_H_

View File

@ -27,8 +27,8 @@ namespace {
spv_result_t SetSpvHeader(void* builder, spv_endianness_t, uint32_t magic,
uint32_t version, uint32_t generator,
uint32_t id_bound, uint32_t reserved) {
reinterpret_cast<ir::IrLoader*>(builder)
->SetModuleHeader(magic, version, generator, id_bound, reserved);
reinterpret_cast<ir::IrLoader*>(builder)->SetModuleHeader(
magic, version, generator, id_bound, reserved);
return SPV_SUCCESS;
};

View File

@ -27,9 +27,9 @@ namespace spvtools {
// specifies number of words in |binary|. The |binary| will be decoded
// according to the given target |env|. Returns nullptr if erors occur and
// sends the errors to |consumer|.
std::unique_ptr<ir::Module> BuildModule(
spv_target_env env, MessageConsumer consumer, const uint32_t* binary,
size_t size);
std::unique_ptr<ir::Module> BuildModule(spv_target_env env,
MessageConsumer consumer,
const uint32_t* binary, size_t size);
// Builds and returns an ir::Module from the given SPIR-V assembly |text|.
// The |text| will be encoded according to the given target |env|. Returns

View File

@ -574,31 +574,21 @@ void CommonUniformElimPass::InitExtensions() {
extensions_whitelist_.clear();
extensions_whitelist_.insert({
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot", "SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float", "SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote", "SPV_KHR_16bit_storage", "SPV_KHR_device_group",
"SPV_KHR_multiview", "SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2", "SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_NV_geometry_shader_passthrough", "SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
// SPV_KHR_variable_pointers
// Currently do not support extended pointer expressions
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_AMD_gpu_shader_int16", "SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
});
}
} // namespace opt
} // namespace spvtools

View File

@ -24,23 +24,23 @@
#include <unordered_set>
#include <utility>
#include "def_use_manager.h"
#include "decoration_manager.h"
#include "module.h"
#include "basic_block.h"
#include "pass.h"
#include "decoration_manager.h"
#include "def_use_manager.h"
#include "ir_context.h"
#include "module.h"
#include "pass.h"
namespace spvtools {
namespace opt {
// See optimizer.hpp for documentation.
class CommonUniformElimPass : public Pass {
using cbb_ptr = const ir::BasicBlock*;
using cbb_ptr = const ir::BasicBlock*;
public:
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
CommonUniformElimPass();
const char* name() const override { return "eliminate-common-uniform"; }
@ -72,7 +72,8 @@ class CommonUniformElimPass : public Pass {
// Given an OpAccessChain instruction, return true
// if the accessed variable belongs to a volatile
// decorated object or member of a struct type
bool IsAccessChainToVolatileStructType(const ir::Instruction &AccessChainInst);
bool IsAccessChainToVolatileStructType(
const ir::Instruction& AccessChainInst);
// Given an OpLoad instruction, return true if
// OpLoad has a Volatile Memory Access flag or if
@ -96,15 +97,14 @@ class CommonUniformElimPass : public Pass {
// Replace all instances of load's id with replId and delete load
// and its access chain, if any
void ReplaceAndDeleteLoad(ir::Instruction* loadInst,
uint32_t replId,
ir::Instruction* ptrInst);
void ReplaceAndDeleteLoad(ir::Instruction* loadInst, uint32_t replId,
ir::Instruction* ptrInst);
// For the (constant index) access chain ptrInst, create an
// equivalent load and extract
void GenACLoadRepl(const ir::Instruction* ptrInst,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts,
uint32_t* resultId);
std::vector<std::unique_ptr<ir::Instruction>>* newInsts,
uint32_t* resultId);
// Return true if all indices are constant
bool IsConstantIndexAccessChain(ir::Instruction* acp);
@ -132,14 +132,15 @@ class CommonUniformElimPass : public Pass {
// TODO(dnovillo): This pass computes structured order slightly different
// than the implementation in class Pass. Can this be re-factored?
void ComputeStructuredOrder(ir::Function* func,
std::list<ir::BasicBlock*>* order);
std::list<ir::BasicBlock*>* order);
// Eliminate loads of uniform variables which have previously been loaded.
// If first load is in control flow, move it to first block of function.
// Most effective if preceded by UniformAccessChainRemoval().
bool CommonUniformLoadElimination(ir::Function* func);
// Eliminate loads of uniform sampler and image variables which have previously
// Eliminate loads of uniform sampler and image variables which have
// previously
// been loaded in the same block for types whose loads cannot cross blocks.
bool CommonUniformLoadElimBlock(ir::Function* func);
@ -150,11 +151,11 @@ class CommonUniformElimPass : public Pass {
bool CommonExtractElimination(ir::Function* func);
// For function |func|, first change all uniform constant index
// access chain loads into equivalent composite extracts. Then consolidate
// access chain loads into equivalent composite extracts. Then consolidate
// identical uniform loads into one uniform load. Finally, consolidate
// identical uniform extracts into one uniform extract. This may require
// moving a load or extract to a point which dominates all uses.
// Return true if func is modified.
// Return true if func is modified.
//
// This pass requires the function to have structured control flow ie shader
// capability. It also requires logical addressing ie Addresses capability
@ -185,8 +186,9 @@ class CommonUniformElimPass : public Pass {
// Map of extract composite ids to map of indices to insts
// TODO(greg-lunarg): Consider std::vector.
std::unordered_map<uint32_t, std::unordered_map<uint32_t,
std::list<ir::Instruction*>>> comp2idx2inst_;
std::unordered_map<uint32_t,
std::unordered_map<uint32_t, std::list<ir::Instruction*>>>
comp2idx2inst_;
// Extensions supported by this pass.
std::unordered_set<std::string> extensions_whitelist_;
@ -201,4 +203,3 @@ class CommonUniformElimPass : public Pass {
} // namespace spvtools
#endif // LIBSPIRV_OPT_SSAMEM_PASS_H_

View File

@ -30,35 +30,38 @@ Pass::Status CompactIdsPass::Process(ir::IRContext* c) {
bool modified = false;
std::unordered_map<uint32_t, uint32_t> result_id_mapping;
c->module()->ForEachInst([&result_id_mapping, &modified] (Instruction* inst) {
auto operand = inst->begin();
while (operand != inst->end()) {
const auto type = operand->type;
if (spvIsIdType(type)) {
assert(operand->words.size() == 1);
uint32_t& id = operand->words[0];
auto it = result_id_mapping.find(id);
if (it == result_id_mapping.end()) {
const uint32_t new_id =
static_cast<uint32_t>(result_id_mapping.size()) + 1;
const auto insertion_result = result_id_mapping.emplace(id, new_id);
it = insertion_result.first;
assert(insertion_result.second);
}
if (id != it->second) {
modified = true;
id = it->second;
// Update data cached in the instruction object.
if (type == SPV_OPERAND_TYPE_RESULT_ID) {
inst->SetResultId(id);
} else if (type == SPV_OPERAND_TYPE_TYPE_ID) {
inst->SetResultType(id);
c->module()->ForEachInst(
[&result_id_mapping, &modified](Instruction* inst) {
auto operand = inst->begin();
while (operand != inst->end()) {
const auto type = operand->type;
if (spvIsIdType(type)) {
assert(operand->words.size() == 1);
uint32_t& id = operand->words[0];
auto it = result_id_mapping.find(id);
if (it == result_id_mapping.end()) {
const uint32_t new_id =
static_cast<uint32_t>(result_id_mapping.size()) + 1;
const auto insertion_result =
result_id_mapping.emplace(id, new_id);
it = insertion_result.first;
assert(insertion_result.second);
}
if (id != it->second) {
modified = true;
id = it->second;
// Update data cached in the instruction object.
if (type == SPV_OPERAND_TYPE_RESULT_ID) {
inst->SetResultId(id);
} else if (type == SPV_OPERAND_TYPE_TYPE_ID) {
inst->SetResultType(id);
}
}
}
++operand;
}
}
++operand;
}
}, true);
},
true);
if (modified)
c->SetIdBound(static_cast<uint32_t>(result_id_mapping.size() + 1));

View File

@ -15,9 +15,9 @@
#ifndef LIBSPIRV_OPT_COMPACT_IDS_PASS_H_
#define LIBSPIRV_OPT_COMPACT_IDS_PASS_H_
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {

View File

@ -29,7 +29,7 @@ const uint32_t kBranchCondTrueLabIdInIdx = 1;
const uint32_t kBranchCondFalseLabIdInIdx = 2;
const uint32_t kSelectionMergeMergeBlockIdInIdx = 0;
} // anonymous namespace
} // anonymous namespace
bool DeadBranchElimPass::GetConstCondition(uint32_t condId, bool* condVal) {
bool condIsConst;
@ -45,14 +45,11 @@ bool DeadBranchElimPass::GetConstCondition(uint32_t condId, bool* condVal) {
} break;
case SpvOpLogicalNot: {
bool negVal;
condIsConst = GetConstCondition(cInst->GetSingleWordInOperand(0),
&negVal);
if (condIsConst)
*condVal = !negVal;
} break;
default: {
condIsConst = false;
condIsConst =
GetConstCondition(cInst->GetSingleWordInOperand(0), &negVal);
if (condIsConst) *condVal = !negVal;
} break;
default: { condIsConst = false; } break;
}
return condIsConst;
}
@ -63,13 +60,11 @@ bool DeadBranchElimPass::GetConstInteger(uint32_t selId, uint32_t* selVal) {
ir::Instruction* typeInst = get_def_use_mgr()->GetDef(typeId);
if (!typeInst || (typeInst->opcode() != SpvOpTypeInt)) return false;
// TODO(greg-lunarg): Support non-32 bit ints
if (typeInst->GetSingleWordInOperand(0) != 32)
return false;
if (typeInst->GetSingleWordInOperand(0) != 32) return false;
if (sInst->opcode() == SpvOpConstant) {
*selVal = sInst->GetSingleWordInOperand(0);
return true;
}
else if (sInst->opcode() == SpvOpConstantNull) {
} else if (sInst->opcode() == SpvOpConstantNull) {
*selVal = 0;
return true;
}
@ -77,46 +72,47 @@ bool DeadBranchElimPass::GetConstInteger(uint32_t selId, uint32_t* selVal) {
}
void DeadBranchElimPass::AddBranch(uint32_t labelId, ir::BasicBlock* bp) {
std::unique_ptr<ir::Instruction> newBranch(
new ir::Instruction(SpvOpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}}}));
std::unique_ptr<ir::Instruction> newBranch(new ir::Instruction(
SpvOpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}}}));
get_def_use_mgr()->AnalyzeInstDefUse(&*newBranch);
bp->AddInstruction(std::move(newBranch));
}
void DeadBranchElimPass::AddSelectionMerge(uint32_t labelId,
ir::BasicBlock* bp) {
std::unique_ptr<ir::Instruction> newMerge(
new ir::Instruction(SpvOpSelectionMerge, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {0}}}));
ir::BasicBlock* bp) {
std::unique_ptr<ir::Instruction> newMerge(new ir::Instruction(
SpvOpSelectionMerge, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {labelId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {0}}}));
get_def_use_mgr()->AnalyzeInstDefUse(&*newMerge);
bp->AddInstruction(std::move(newMerge));
}
void DeadBranchElimPass::AddBranchConditional(uint32_t condId,
uint32_t trueLabId, uint32_t falseLabId, ir::BasicBlock* bp) {
std::unique_ptr<ir::Instruction> newBranchCond(
new ir::Instruction(SpvOpBranchConditional, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {condId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {trueLabId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {falseLabId}}}));
uint32_t trueLabId,
uint32_t falseLabId,
ir::BasicBlock* bp) {
std::unique_ptr<ir::Instruction> newBranchCond(new ir::Instruction(
SpvOpBranchConditional, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {condId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {trueLabId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {falseLabId}}}));
get_def_use_mgr()->AnalyzeInstDefUse(&*newBranchCond);
bp->AddInstruction(std::move(newBranchCond));
}
bool DeadBranchElimPass::GetSelectionBranch(ir::BasicBlock* bp,
ir::Instruction** branchInst, ir::Instruction** mergeInst,
uint32_t *condId) {
ir::Instruction** branchInst,
ir::Instruction** mergeInst,
uint32_t* condId) {
auto ii = bp->end();
--ii;
*branchInst = &*ii;
if (ii == bp->begin())
return false;
if (ii == bp->begin()) return false;
--ii;
*mergeInst = &*ii;
if ((*mergeInst)->opcode() != SpvOpSelectionMerge)
return false;
if ((*mergeInst)->opcode() != SpvOpSelectionMerge) return false;
// SPIR-V says the terminator for an OpSelectionMerge must be
// either a conditional branch or a switch.
assert((*branchInst)->opcode() == SpvOpBranchConditional ||
@ -128,8 +124,7 @@ bool DeadBranchElimPass::GetSelectionBranch(ir::BasicBlock* bp,
bool DeadBranchElimPass::HasNonPhiNonBackedgeRef(uint32_t labelId) {
analysis::UseList* uses = get_def_use_mgr()->GetUses(labelId);
if (uses == nullptr)
return false;
if (uses == nullptr) return false;
for (auto u : *uses) {
if (u.inst->opcode() != SpvOpPhi &&
backedges_.find(u.inst) == backedges_.end())
@ -147,24 +142,22 @@ void DeadBranchElimPass::ComputeBackEdges(
visited.insert((*bi)->id());
auto ii = (*bi)->end();
--ii;
switch(ii->opcode()) {
switch (ii->opcode()) {
case SpvOpBranch: {
const uint32_t labId = ii->GetSingleWordInOperand(
kBranchTargetLabIdInIdx);
if (visited.find(labId) != visited.end())
backedges_.insert(&*ii);
const uint32_t labId =
ii->GetSingleWordInOperand(kBranchTargetLabIdInIdx);
if (visited.find(labId) != visited.end()) backedges_.insert(&*ii);
} break;
case SpvOpBranchConditional: {
const uint32_t tLabId = ii->GetSingleWordInOperand(
kBranchCondTrueLabIdInIdx);
const uint32_t tLabId =
ii->GetSingleWordInOperand(kBranchCondTrueLabIdInIdx);
if (visited.find(tLabId) != visited.end()) {
backedges_.insert(&*ii);
break;
}
const uint32_t fLabId = ii->GetSingleWordInOperand(
kBranchCondFalseLabIdInIdx);
if (visited.find(fLabId) != visited.end())
backedges_.insert(&*ii);
const uint32_t fLabId =
ii->GetSingleWordInOperand(kBranchCondFalseLabIdInIdx);
if (visited.find(fLabId) != visited.end()) backedges_.insert(&*ii);
} break;
default:
break;
@ -181,53 +174,45 @@ bool DeadBranchElimPass::EliminateDeadBranches(ir::Function* func) {
bool modified = false;
for (auto bi = structuredOrder.begin(); bi != structuredOrder.end(); ++bi) {
// Skip blocks that are already in the elimination set
if (elimBlocks.find(*bi) != elimBlocks.end())
continue;
if (elimBlocks.find(*bi) != elimBlocks.end()) continue;
// Skip blocks that don't have conditional branch preceded
// by OpSelectionMerge
ir::Instruction* br;
ir::Instruction* mergeInst;
uint32_t condId;
if (!GetSelectionBranch(*bi, &br, &mergeInst, &condId))
continue;
if (!GetSelectionBranch(*bi, &br, &mergeInst, &condId)) continue;
// If constant condition/selector, replace conditional branch/switch
// with unconditional branch and delete merge
uint32_t liveLabId;
if (br->opcode() == SpvOpBranchConditional) {
bool condVal;
if (!GetConstCondition(condId, &condVal))
continue;
liveLabId = (condVal == true) ?
br->GetSingleWordInOperand(kBranchCondTrueLabIdInIdx) :
br->GetSingleWordInOperand(kBranchCondFalseLabIdInIdx);
}
else {
if (!GetConstCondition(condId, &condVal)) continue;
liveLabId = (condVal == true)
? br->GetSingleWordInOperand(kBranchCondTrueLabIdInIdx)
: br->GetSingleWordInOperand(kBranchCondFalseLabIdInIdx);
} else {
assert(br->opcode() == SpvOpSwitch);
// Search switch operands for selector value, set liveLabId to
// corresponding label, use default if not found
uint32_t selVal;
if (!GetConstInteger(condId, &selVal))
continue;
if (!GetConstInteger(condId, &selVal)) continue;
uint32_t icnt = 0;
uint32_t caseVal;
br->ForEachInOperand(
[&icnt,&caseVal,&selVal,&liveLabId](const uint32_t* idp) {
if (icnt == 1) {
// Start with default label
liveLabId = *idp;
}
else if (icnt > 1) {
if (icnt % 2 == 0) {
caseVal = *idp;
}
else {
if (caseVal == selVal)
[&icnt, &caseVal, &selVal, &liveLabId](const uint32_t* idp) {
if (icnt == 1) {
// Start with default label
liveLabId = *idp;
}
}
++icnt;
});
} else if (icnt > 1) {
if (icnt % 2 == 0) {
caseVal = *idp;
} else {
if (caseVal == selVal) liveLabId = *idp;
}
}
++icnt;
});
}
const uint32_t mergeLabId =
@ -258,36 +243,30 @@ bool DeadBranchElimPass::EliminateDeadBranches(ir::Function* func) {
KillAllInsts(*dbi);
elimBlocks.insert(*dbi);
++dbi;
if (dbi == structuredOrder.end())
break;
if (dbi == structuredOrder.end()) break;
dLabId = (*dbi)->id();
}
// If last block reached, look for next dead branch
if (dbi == structuredOrder.end())
continue;
if (dbi == structuredOrder.end()) continue;
// Create set of dead predecessors in preparation for phi update.
// Add the header block if the live branch is not the merge block.
std::unordered_set<ir::BasicBlock*> deadPreds(elimBlocks);
if (liveLabId != dLabId)
deadPreds.insert(*bi);
if (liveLabId != dLabId) deadPreds.insert(*bi);
// Update phi instructions in terminating block.
for (auto pii = (*dbi)->begin(); ; ++pii) {
for (auto pii = (*dbi)->begin();; ++pii) {
// Skip NoOps, break at end of phis
SpvOp op = pii->opcode();
if (op == SpvOpNop)
continue;
if (op != SpvOpPhi)
break;
if (op == SpvOpNop) continue;
if (op != SpvOpPhi) break;
// Count phi's live predecessors with lcnt and remember last one
// with lidx.
uint32_t lcnt = 0;
uint32_t lidx = 0;
uint32_t icnt = 0;
pii->ForEachInId(
[&deadPreds,&icnt,&lcnt,&lidx,this](uint32_t* idp) {
pii->ForEachInId([&deadPreds, &icnt, &lcnt, &lidx, this](uint32_t* idp) {
if (icnt % 2 == 1) {
if (deadPreds.find(cfg()->block(*idp)) == deadPreds.end()) {
++lcnt;
@ -300,8 +279,7 @@ bool DeadBranchElimPass::EliminateDeadBranches(ir::Function* func) {
uint32_t replId;
if (lcnt == 1) {
replId = pii->GetSingleWordInOperand(lidx);
}
else {
} else {
// Otherwise create new phi eliminating dead predecessor entries
assert(lcnt > 1);
replId = TakeNextId();
@ -309,20 +287,19 @@ bool DeadBranchElimPass::EliminateDeadBranches(ir::Function* func) {
icnt = 0;
uint32_t lastId;
pii->ForEachInId(
[&deadPreds,&icnt,&phi_in_opnds,&lastId,this](uint32_t* idp) {
if (icnt % 2 == 1) {
if (deadPreds.find(cfg()->block(*idp)) == deadPreds.end()) {
phi_in_opnds.push_back(
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {lastId}});
phi_in_opnds.push_back(
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {*idp}});
}
}
else {
lastId = *idp;
}
++icnt;
});
[&deadPreds, &icnt, &phi_in_opnds, &lastId, this](uint32_t* idp) {
if (icnt % 2 == 1) {
if (deadPreds.find(cfg()->block(*idp)) == deadPreds.end()) {
phi_in_opnds.push_back(
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {lastId}});
phi_in_opnds.push_back(
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {*idp}});
}
} else {
lastId = *idp;
}
++icnt;
});
std::unique_ptr<ir::Instruction> newPhi(new ir::Instruction(
SpvOpPhi, pii->type_id(), replId, phi_in_opnds));
get_def_use_mgr()->AnalyzeInstDefUse(&*newPhi);
@ -337,7 +314,7 @@ bool DeadBranchElimPass::EliminateDeadBranches(ir::Function* func) {
}
// Erase dead blocks
for (auto ebi = func->begin(); ebi != func->end(); )
for (auto ebi = func->begin(); ebi != func->end();)
if (elimBlocks.find(&*ebi) != elimBlocks.end())
ebi = ebi.Erase();
else
@ -355,8 +332,8 @@ void DeadBranchElimPass::Initialize(ir::IRContext* c) {
bool DeadBranchElimPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : get_module()->extensions()) {
const char* extName = reinterpret_cast<const char*>(
&ei.GetInOperand(0).words[0]);
const char* extName =
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
return false;
}
@ -364,7 +341,7 @@ bool DeadBranchElimPass::AllExtensionsSupported() const {
}
Pass::Status DeadBranchElimPass::ProcessImpl() {
// Current functionality assumes structured control flow.
// Current functionality assumes structured control flow.
// TODO(greg-lunarg): Handle non-structured control-flow.
if (!get_module()->HasCapability(SpvCapabilityShader))
return Status::SuccessWithoutChange;
@ -372,11 +349,9 @@ Pass::Status DeadBranchElimPass::ProcessImpl() {
// support required in KillNamesAndDecorates().
// TODO(greg-lunarg): Add support for OpGroupDecorate
for (auto& ai : get_module()->annotations())
if (ai.opcode() == SpvOpGroupDecorate)
return Status::SuccessWithoutChange;
if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange;
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process all entry point functions
ProcessFunction pfn = [this](ir::Function* fp) {
return EliminateDeadBranches(fp);
@ -395,31 +370,30 @@ Pass::Status DeadBranchElimPass::Process(ir::IRContext* module) {
void DeadBranchElimPass::InitExtensions() {
extensions_whitelist_.clear();
extensions_whitelist_.insert({
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
"SPV_KHR_variable_pointers",
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
"SPV_KHR_variable_pointers",
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
});
}
} // namespace opt
} // namespace spvtools

View File

@ -17,7 +17,6 @@
#ifndef LIBSPIRV_OPT_DEAD_BRANCH_ELIM_PASS_H_
#define LIBSPIRV_OPT_DEAD_BRANCH_ELIM_PASS_H_
#include <algorithm>
#include <map>
#include <queue>
@ -27,20 +26,19 @@
#include "basic_block.h"
#include "def_use_manager.h"
#include "module.h"
#include "mem_pass.h"
#include "module.h"
namespace spvtools {
namespace opt {
// See optimizer.hpp for documentation.
class DeadBranchElimPass : public MemPass {
using cbb_ptr = const ir::BasicBlock*;
public:
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
DeadBranchElimPass();
const char* name() const override { return "eliminate-dead-branches"; }
@ -64,13 +62,13 @@ class DeadBranchElimPass : public MemPass {
// Add conditional branch of |condId|, |trueLabId| and |falseLabId| to end
// of block |bp|.
void AddBranchConditional(uint32_t condId, uint32_t trueLabId,
uint32_t falseLabId, ir::BasicBlock* bp);
uint32_t falseLabId, ir::BasicBlock* bp);
// If block |bp| contains conditional branch or switch preceeded by an
// OpSelctionMerge, return true and return branch and merge instructions
// in |branchInst| and |mergeInst| and the conditional id in |condId|.
// in |branchInst| and |mergeInst| and the conditional id in |condId|.
bool GetSelectionBranch(ir::BasicBlock* bp, ir::Instruction** branchInst,
ir::Instruction** mergeInst, uint32_t *condId);
ir::Instruction** mergeInst, uint32_t* condId);
// Return true if |labelId| has any non-phi, non-backedge references
bool HasNonPhiNonBackedgeRef(uint32_t labelId);
@ -106,4 +104,3 @@ class DeadBranchElimPass : public MemPass {
} // namespace spvtools
#endif // LIBSPIRV_OPT_DEAD_BRANCH_ELIM_PASS_H_

View File

@ -24,7 +24,8 @@ namespace opt {
Pass::Status DeadVariableElimination::Process(ir::IRContext* c) {
// The algorithm will compute the reference count for every global variable.
// Anything with a reference count of 0 will then be deleted. For variables
// that might have references that are not explicit in this context, we use the
// that might have references that are not explicit in this context, we use
// the
// value kMustKeep as the reference count.
InitializeProcessing(c);
@ -61,7 +62,7 @@ Pass::Status DeadVariableElimination::Process(ir::IRContext* c) {
count = std::count_if(
uses->begin(), uses->end(), [](const analysis::Use& u) {
return (!ir::IsAnnotationInst(u.inst->opcode()) &&
u.inst->opcode() != SpvOpName);
u.inst->opcode() != SpvOpName);
});
}
}
@ -85,7 +86,7 @@ Pass::Status DeadVariableElimination::Process(ir::IRContext* c) {
void DeadVariableElimination::DeleteVariable(uint32_t result_id) {
ir::Instruction* inst = get_def_use_mgr()->GetDef(result_id);
assert(inst->opcode() == SpvOpVariable &&
"Should not be trying to delete anything other than an OpVariable.");
"Should not be trying to delete anything other than an OpVariable.");
// Look for an initializer that references another variable. We need to know
// if that variable can be deleted after the reference is removed.

View File

@ -15,8 +15,8 @@
#ifndef SPIRV_TOOLS_DEAD_VARIABLE_ELIMINATION_H
#define SPIRV_TOOLS_DEAD_VARIABLE_ELIMINATION_H
#include <unordered_map>
#include <climits>
#include <unordered_map>
#include "decoration_manager.h"
#include "mem_pass.h"

View File

@ -29,8 +29,9 @@ void DecorationManager::RemoveDecorationsFrom(uint32_t id, bool keep_linkage) {
case SpvOpDecorate:
case SpvOpDecorateId:
case SpvOpMemberDecorate:
if (!(keep_linkage && inst->GetSingleWordInOperand(1u) ==
SpvDecorationLinkageAttributes))
if (!(keep_linkage &&
inst->GetSingleWordInOperand(1u) ==
SpvDecorationLinkageAttributes))
inst->ToNop();
break;
case SpvOpGroupDecorate:
@ -229,9 +230,9 @@ std::vector<T> DecorationManager::InternalGetDecorationsFor(
return decorations;
}
void DecorationManager::ForEachDecoration(uint32_t id,
uint32_t decoration,
std::function<void(const ir::Instruction&)> f) const {
void DecorationManager::ForEachDecoration(
uint32_t id, uint32_t decoration,
std::function<void(const ir::Instruction&)> f) const {
auto decoration_list = id_to_decoration_insts_.find(id);
if (decoration_list != id_to_decoration_insts_.end()) {
for (const ir::Instruction* inst : decoration_list->second) {

View File

@ -31,8 +31,7 @@ void DefUseManager::AnalyzeInstDef(ir::Instruction* inst) {
ClearInst(iter->second);
}
id_to_def_[def_id] = inst;
}
else {
} else {
ClearInst(inst);
}
}
@ -46,16 +45,16 @@ void DefUseManager::AnalyzeInstUse(ir::Instruction* inst) {
for (uint32_t i = 0; i < inst->NumOperands(); ++i) {
switch (inst->GetOperand(i).type) {
// For any id type but result id type
case SPV_OPERAND_TYPE_ID:
case SPV_OPERAND_TYPE_TYPE_ID:
case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
case SPV_OPERAND_TYPE_SCOPE_ID: {
uint32_t use_id = inst->GetSingleWordOperand(i);
id_to_uses_[use_id].push_back({ inst, i });
inst_to_used_ids_[inst].push_back(use_id);
} break;
default:
break;
case SPV_OPERAND_TYPE_ID:
case SPV_OPERAND_TYPE_TYPE_ID:
case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
case SPV_OPERAND_TYPE_SCOPE_ID: {
uint32_t use_id = inst->GetSingleWordOperand(i);
id_to_uses_[use_id].push_back({inst, i});
inst_to_used_ids_[inst].push_back(use_id);
} break;
default:
break;
}
}
}
@ -101,7 +100,6 @@ std::vector<ir::Instruction*> DefUseManager::GetAnnotations(uint32_t id) const {
return annos;
}
void DefUseManager::AnalyzeDefUse(ir::Module* module) {
if (!module) return;
module->ForEachInst(std::bind(&DefUseManager::AnalyzeInstDefUse, this,

View File

@ -49,9 +49,7 @@ class DefUseManager {
// will be communicated to the outside via the given message |consumer|. This
// instance only keeps a reference to the |consumer|, so the |consumer| should
// outlive this instance.
DefUseManager(ir::Module* module) {
AnalyzeDefUse(module);
}
DefUseManager(ir::Module* module) { AnalyzeDefUse(module); }
DefUseManager(const DefUseManager&) = delete;
DefUseManager(DefUseManager&&) = delete;
@ -105,8 +103,8 @@ class DefUseManager {
// structures in this class. Does nothing if |module| is nullptr.
void AnalyzeDefUse(ir::Module* module);
IdToDefMap id_to_def_; // Mapping from ids to their definitions
IdToUsesMap id_to_uses_; // Mapping from ids to their uses
IdToDefMap id_to_def_; // Mapping from ids to their definitions
IdToUsesMap id_to_uses_; // Mapping from ids to their uses
// Mapping from instructions to the ids used in the instruction.
InstToUsedIdsMap inst_to_used_ids_;
};

View File

@ -19,9 +19,9 @@
#include <unordered_set>
#include "def_use_manager.h"
#include "ir_context.h"
#include "log.h"
#include "reflect.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {
@ -36,7 +36,8 @@ Pass::Status EliminateDeadConstantPass::Process(ir::IRContext* irContext) {
for (auto* c : constants) {
uint32_t const_id = c->result_id();
size_t count = 0;
if (analysis::UseList* uses = irContext->get_def_use_mgr()->GetUses(const_id)) {
if (analysis::UseList* uses =
irContext->get_def_use_mgr()->GetUses(const_id)) {
count =
std::count_if(uses->begin(), uses->end(), [](const analysis::Use& u) {
return !(ir::IsAnnotationInst(u.inst->opcode()) ||
@ -68,7 +69,8 @@ Pass::Status EliminateDeadConstantPass::Process(ir::IRContext* irContext) {
continue;
}
uint32_t operand_id = inst->GetSingleWordInOperand(i);
ir::Instruction* def_inst = irContext->get_def_use_mgr()->GetDef(operand_id);
ir::Instruction* def_inst =
irContext->get_def_use_mgr()->GetDef(operand_id);
// If the use_count does not have any count for the def_inst,
// def_inst must not be a constant, and should be ignored here.
if (!use_counts.count(def_inst)) {
@ -94,7 +96,8 @@ Pass::Status EliminateDeadConstantPass::Process(ir::IRContext* irContext) {
// constants.
std::unordered_set<ir::Instruction*> dead_others;
for (auto* dc : dead_consts) {
if (analysis::UseList* uses = irContext->get_def_use_mgr()->GetUses(dc->result_id())) {
if (analysis::UseList* uses =
irContext->get_def_use_mgr()->GetUses(dc->result_id())) {
for (const auto& u : *uses) {
if (ir::IsAnnotationInst(u.inst->opcode()) ||
ir::IsDebug1Inst(u.inst->opcode()) ||

View File

@ -15,9 +15,9 @@
#ifndef LIBSPIRV_OPT_ELIMINATE_DEAD_CONSTANT_PASS_H_
#define LIBSPIRV_OPT_ELIMINATE_DEAD_CONSTANT_PASS_H_
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {

View File

@ -16,9 +16,9 @@
#include "ir_context.h"
#include <cassert>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace spvtools {
namespace opt {

View File

@ -15,9 +15,9 @@
#ifndef LIBSPIRV_OPT_FLATTEN_DECORATION_PASS_H_
#define LIBSPIRV_OPT_FLATTEN_DECORATION_PASS_H_
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {

View File

@ -15,8 +15,8 @@
#ifndef LIBSPIRV_UTIL_FOLD_H_
#define LIBSPIRV_UTIL_FOLD_H_
#include "def_use_manager.h"
#include "constants.h"
#include "def_use_manager.h"
#include <cstdint>
#include <vector>

View File

@ -19,8 +19,8 @@
#include <tuple>
#include "constants.h"
#include "make_unique.h"
#include "ir_context.h"
#include "make_unique.h"
namespace spvtools {
namespace opt {
@ -245,7 +245,8 @@ std::vector<uint32_t> OperateVectors(
FoldSpecConstantOpAndCompositePass::FoldSpecConstantOpAndCompositePass()
: max_id_(0), type_mgr_(nullptr), id_to_const_val_() {}
Pass::Status FoldSpecConstantOpAndCompositePass::Process(ir::IRContext* irContext) {
Pass::Status FoldSpecConstantOpAndCompositePass::Process(
ir::IRContext* irContext) {
Initialize(irContext);
return ProcessImpl(irContext);
}

View File

@ -21,10 +21,10 @@
#include "constants.h"
#include "def_use_manager.h"
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "type_manager.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {

View File

@ -15,9 +15,9 @@
#ifndef LIBSPIRV_OPT_FREEZE_SPEC_CONSTANT_VALUE_PASS_H_
#define LIBSPIRV_OPT_FREEZE_SPEC_CONSTANT_VALUE_PASS_H_
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {

View File

@ -64,8 +64,9 @@ class Function {
// Returns function's id
inline uint32_t result_id() const { return def_inst_->result_id(); }
// // Returns function's type id
// inline uint32_t type_id() const { return def_inst_->GetSingleWordInOperand(1u); }
// // Returns function's type id
// inline uint32_t type_id() const { return
// def_inst_->GetSingleWordInOperand(1u); }
// Returns function's return type id
inline uint32_t type_id() const { return def_inst_->type_id(); }

View File

@ -31,13 +31,13 @@ bool InlineExhaustivePass::InlineExhaustive(ir::Function* func) {
GenInlineCode(&newBlocks, &newVars, ii, bi);
// If call block is replaced with more than one block, point
// succeeding phis at new last block.
if (newBlocks.size() > 1)
UpdateSucceedingPhis(newBlocks);
if (newBlocks.size() > 1) UpdateSucceedingPhis(newBlocks);
// Replace old calling block with new block(s).
bi = bi.Erase();
bi = bi.InsertBefore(&newBlocks);
// Insert new function variables.
if (newVars.size() > 0) func->begin()->begin().InsertBefore(std::move(newVars));
if (newVars.size() > 0)
func->begin()->begin().InsertBefore(std::move(newVars));
// Restart inlining at beginning of calling block.
ii = bi->begin();
modified = true;

View File

@ -20,19 +20,18 @@
#include <algorithm>
#include <list>
#include <memory>
#include <vector>
#include <unordered_map>
#include <vector>
#include "def_use_manager.h"
#include "module.h"
#include "inline_pass.h"
#include "module.h"
namespace spvtools {
namespace opt {
// See optimizer.hpp for documentation.
class InlineExhaustivePass : public InlinePass {
public:
InlineExhaustivePass();
Status Process(ir::IRContext* c) override;

View File

@ -21,9 +21,9 @@ namespace opt {
namespace {
const uint32_t kTypePointerTypeIdInIdx = 1;
const uint32_t kTypePointerTypeIdInIdx = 1;
} // anonymous namespace
} // anonymous namespace
bool InlineOpaquePass::IsOpaqueType(uint32_t typeId) {
const ir::Instruction* typeInst = get_def_use_mgr()->GetDef(typeId);
@ -33,17 +33,16 @@ bool InlineOpaquePass::IsOpaqueType(uint32_t typeId) {
case SpvOpTypeSampledImage:
return true;
case SpvOpTypePointer:
return IsOpaqueType(typeInst->GetSingleWordInOperand(
kTypePointerTypeIdInIdx));
return IsOpaqueType(
typeInst->GetSingleWordInOperand(kTypePointerTypeIdInIdx));
default:
break;
}
// TODO(greg-lunarg): Handle arrays containing opaque type
if (typeInst->opcode() != SpvOpTypeStruct)
return false;
if (typeInst->opcode() != SpvOpTypeStruct) return false;
// Return true if any member is opaque
int ocnt = 0;
typeInst->ForEachInId([&ocnt,this](const uint32_t* tid) {
typeInst->ForEachInId([&ocnt, this](const uint32_t* tid) {
if (ocnt == 0 && IsOpaqueType(*tid)) ++ocnt;
});
return ocnt > 0;
@ -51,16 +50,14 @@ bool InlineOpaquePass::IsOpaqueType(uint32_t typeId) {
bool InlineOpaquePass::HasOpaqueArgsOrReturn(const ir::Instruction* callInst) {
// Check return type
if (IsOpaqueType(callInst->type_id()))
return true;
if (IsOpaqueType(callInst->type_id())) return true;
// Check args
int icnt = 0;
int ocnt = 0;
callInst->ForEachInId([&icnt,&ocnt,this](const uint32_t *iid) {
callInst->ForEachInId([&icnt, &ocnt, this](const uint32_t* iid) {
if (icnt > 0) {
const ir::Instruction* argInst = get_def_use_mgr()->GetDef(*iid);
if (IsOpaqueType(argInst->type_id()))
++ocnt;
if (IsOpaqueType(argInst->type_id())) ++ocnt;
}
++icnt;
});
@ -79,13 +76,13 @@ bool InlineOpaquePass::InlineOpaque(ir::Function* func) {
GenInlineCode(&newBlocks, &newVars, ii, bi);
// If call block is replaced with more than one block, point
// succeeding phis at new last block.
if (newBlocks.size() > 1)
UpdateSucceedingPhis(newBlocks);
if (newBlocks.size() > 1) UpdateSucceedingPhis(newBlocks);
// Replace old calling block with new block(s).
bi = bi.Erase();
bi = bi.InsertBefore(&newBlocks);
// Insert new function variables.
if (newVars.size() > 0) func->begin()->begin().InsertBefore(std::move(newVars));
if (newVars.size() > 0)
func->begin()->begin().InsertBefore(std::move(newVars));
// Restart inlining at beginning of calling block.
ii = bi->begin();
modified = true;
@ -97,15 +94,11 @@ bool InlineOpaquePass::InlineOpaque(ir::Function* func) {
return modified;
}
void InlineOpaquePass::Initialize(ir::IRContext* c) {
InitializeInline(c);
};
void InlineOpaquePass::Initialize(ir::IRContext* c) { InitializeInline(c); };
Pass::Status InlineOpaquePass::ProcessImpl() {
// Do opaque inlining on each function in entry point call tree
ProcessFunction pfn = [this](ir::Function* fp) {
return InlineOpaque(fp);
};
ProcessFunction pfn = [this](ir::Function* fp) { return InlineOpaque(fp); };
bool modified = ProcessEntryPointCallTree(pfn, get_module());
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}

View File

@ -20,19 +20,18 @@
#include <algorithm>
#include <list>
#include <memory>
#include <vector>
#include <unordered_map>
#include <vector>
#include "def_use_manager.h"
#include "module.h"
#include "inline_pass.h"
#include "module.h"
namespace spvtools {
namespace opt {
// See optimizer.hpp for documentation.
class InlineOpaquePass : public InlinePass {
public:
InlineOpaquePass();
Status Process(ir::IRContext* c) override;

View File

@ -58,25 +58,26 @@ uint32_t InlinePass::AddPointerToType(uint32_t type_id,
}
void InlinePass::AddBranch(uint32_t label_id,
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unique_ptr<ir::Instruction> newBranch(new ir::Instruction(
SpvOpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}}));
SpvOpBranch, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {label_id}}}));
(*block_ptr)->AddInstruction(std::move(newBranch));
}
void InlinePass::AddBranchCond(uint32_t cond_id, uint32_t true_id,
uint32_t false_id, std::unique_ptr<ir::BasicBlock>* block_ptr) {
uint32_t false_id,
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unique_ptr<ir::Instruction> newBranch(new ir::Instruction(
SpvOpBranchConditional, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {false_id}}}));
SpvOpBranchConditional, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cond_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {true_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {false_id}}}));
(*block_ptr)->AddInstruction(std::move(newBranch));
}
void InlinePass::AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unique_ptr<ir::Instruction> newLoopMerge(new ir::Instruction(
SpvOpLoopMerge, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}},
@ -88,8 +89,9 @@ void InlinePass::AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
void InlinePass::AddStore(uint32_t ptr_id, uint32_t val_id,
std::unique_ptr<ir::BasicBlock>* block_ptr) {
std::unique_ptr<ir::Instruction> newStore(new ir::Instruction(
SpvOpStore, 0, 0, {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {val_id}}}));
SpvOpStore, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ptr_id}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {val_id}}}));
(*block_ptr)->AddInstruction(std::move(newStore));
}
@ -108,11 +110,9 @@ std::unique_ptr<ir::Instruction> InlinePass::NewLabel(uint32_t label_id) {
}
uint32_t InlinePass::GetFalseId() {
if (false_id_ != 0)
return false_id_;
if (false_id_ != 0) return false_id_;
false_id_ = get_module()->GetGlobalValue(SpvOpConstantFalse);
if (false_id_ != 0)
return false_id_;
if (false_id_ != 0) return false_id_;
uint32_t boolId = get_module()->GetGlobalValue(SpvOpTypeBool);
if (boolId == 0) {
boolId = TakeNextId();
@ -124,8 +124,7 @@ uint32_t InlinePass::GetFalseId() {
}
void InlinePass::MapParams(
ir::Function* calleeFn,
ir::BasicBlock::iterator call_inst_itr,
ir::Function* calleeFn, ir::BasicBlock::iterator call_inst_itr,
std::unordered_map<uint32_t, uint32_t>* callee2caller) {
int param_idx = 0;
calleeFn->ForEachParam(
@ -186,8 +185,8 @@ void InlinePass::CloneSameBlockOps(
std::unordered_map<uint32_t, uint32_t>* postCallSB,
std::unordered_map<uint32_t, ir::Instruction*>* preCallSB,
std::unique_ptr<ir::BasicBlock>* block_ptr) {
(*inst)
->ForEachInId([&postCallSB, &preCallSB, &block_ptr, this](uint32_t* iid) {
(*inst)->ForEachInId(
[&postCallSB, &preCallSB, &block_ptr, this](uint32_t* iid) {
const auto mapItr = (*postCallSB).find(*iid);
if (mapItr == (*postCallSB).end()) {
const auto mapItr2 = (*preCallSB).find(*iid);
@ -242,11 +241,9 @@ void InlinePass::GenInlineCode(
// Create set of callee result ids. Used to detect forward references
std::unordered_set<uint32_t> callee_result_ids;
calleeFn->ForEachInst([&callee_result_ids](
const ir::Instruction* cpi) {
calleeFn->ForEachInst([&callee_result_ids](const ir::Instruction* cpi) {
const uint32_t rid = cpi->result_id();
if (rid != 0)
callee_result_ids.insert(rid);
if (rid != 0) callee_result_ids.insert(rid);
});
// If the caller is in a single-block loop, and the callee has multiple
@ -333,8 +330,7 @@ void InlinePass::GenInlineCode(
}
new_blk_ptr->AddInstruction(std::move(cp_inst));
}
if (caller_is_loop_header &&
callee_begins_with_structured_header) {
if (caller_is_loop_header && callee_begins_with_structured_header) {
// We can't place both the caller's merge instruction and another
// merge instruction in the same block. So split the calling block.
// Insert an unconditional branch to a new guard block. Later,
@ -366,8 +362,8 @@ void InlinePass::GenInlineCode(
singleTripLoopHeaderId = this->TakeNextId();
AddBranch(singleTripLoopHeaderId, &new_blk_ptr);
new_blocks->push_back(std::move(new_blk_ptr));
new_blk_ptr.reset(new ir::BasicBlock(NewLabel(
singleTripLoopHeaderId)));
new_blk_ptr.reset(
new ir::BasicBlock(NewLabel(singleTripLoopHeaderId)));
returnLabelId = this->TakeNextId();
singleTripLoopContinueId = this->TakeNextId();
AddLoopMerge(returnLabelId, singleTripLoopContinueId, &new_blk_ptr);
@ -475,8 +471,7 @@ void InlinePass::GenInlineCode(
uint32_t nid;
if (mapItr != callee2caller.end()) {
nid = mapItr->second;
}
else {
} else {
nid = this->TakeNextId();
callee2caller[rid] = nid;
}
@ -530,15 +525,14 @@ void InlinePass::UpdateSucceedingPhis(
const auto lastBlk = new_blocks.end() - 1;
const uint32_t firstId = (*firstBlk)->id();
const uint32_t lastId = (*lastBlk)->id();
(*lastBlk)->ForEachSuccessorLabel(
[&firstId, &lastId, this](uint32_t succ) {
ir::BasicBlock* sbp = this->id2block_[succ];
sbp->ForEachPhiInst([&firstId, &lastId](ir::Instruction* phi) {
phi->ForEachInId([&firstId, &lastId](uint32_t* id) {
if (*id == firstId) *id = lastId;
});
});
(*lastBlk)->ForEachSuccessorLabel([&firstId, &lastId, this](uint32_t succ) {
ir::BasicBlock* sbp = this->id2block_[succ];
sbp->ForEachPhiInst([&firstId, &lastId](ir::Instruction* phi) {
phi->ForEachInId([&firstId, &lastId](uint32_t* id) {
if (*id == firstId) *id = lastId;
});
});
});
}
bool InlinePass::HasMultipleReturns(ir::Function* func) {
@ -547,7 +541,7 @@ bool InlinePass::HasMultipleReturns(ir::Function* func) {
for (auto& blk : *func) {
auto terminal_ii = blk.cend();
--terminal_ii;
if (terminal_ii->opcode() == SpvOpReturn ||
if (terminal_ii->opcode() == SpvOpReturn ||
terminal_ii->opcode() == SpvOpReturnValue) {
if (seenReturn) {
multipleReturns = true;
@ -559,7 +553,6 @@ bool InlinePass::HasMultipleReturns(ir::Function* func) {
return multipleReturns;
}
void InlinePass::ComputeStructuredSuccessors(ir::Function* func) {
// If header, make merge block first successor.
for (auto& blk : *func) {
@ -584,8 +577,7 @@ InlinePass::GetBlocksFunction InlinePass::StructuredSuccessorsFunction() {
bool InlinePass::HasNoReturnInLoop(ir::Function* func) {
// If control not structured, do not do loop/return analysis
// TODO: Analyze returns in non-structured control flow
if (!get_module()->HasCapability(SpvCapabilityShader))
return false;
if (!get_module()->HasCapability(SpvCapabilityShader)) return false;
// Compute structured block order. This order has the property
// that dominators are before all blocks they dominate and merge blocks
// are after all blocks that are in the control constructs of their header.
@ -594,32 +586,30 @@ bool InlinePass::HasNoReturnInLoop(ir::Function* func) {
auto ignore_edge = [](cbb_ptr, cbb_ptr) {};
std::list<const ir::BasicBlock*> structuredOrder;
spvtools::CFA<ir::BasicBlock>::DepthFirstTraversal(
&*func->begin(), StructuredSuccessorsFunction(), ignore_block,
[&](cbb_ptr b) { structuredOrder.push_front(b); }, ignore_edge);
&*func->begin(), StructuredSuccessorsFunction(), ignore_block,
[&](cbb_ptr b) { structuredOrder.push_front(b); }, ignore_edge);
// Search for returns in loops. Only need to track outermost loop
bool return_in_loop = false;
uint32_t outerLoopMergeId = 0;
for (auto& blk : structuredOrder) {
// Exiting current outer loop
if (blk->id() == outerLoopMergeId)
outerLoopMergeId = 0;
if (blk->id() == outerLoopMergeId) outerLoopMergeId = 0;
// Return block
auto terminal_ii = blk->cend();
--terminal_ii;
if (terminal_ii->opcode() == SpvOpReturn ||
if (terminal_ii->opcode() == SpvOpReturn ||
terminal_ii->opcode() == SpvOpReturnValue) {
if (outerLoopMergeId != 0) {
return_in_loop = true;
break;
}
}
else if (terminal_ii != blk->cbegin()) {
} else if (terminal_ii != blk->cbegin()) {
auto merge_ii = terminal_ii;
--merge_ii;
// Entering outermost loop
if (merge_ii->opcode() == SpvOpLoopMerge && outerLoopMergeId == 0)
outerLoopMergeId = merge_ii->GetSingleWordOperand(
kSpvLoopMergeMergeBlockId);
outerLoopMergeId =
merge_ii->GetSingleWordOperand(kSpvLoopMergeMergeBlockId);
}
}
return !return_in_loop;
@ -633,14 +623,12 @@ void InlinePass::AnalyzeReturns(ir::Function* func) {
}
multi_return_funcs_.insert(func->result_id());
// If multiple returns, see if any are in a loop
if (HasNoReturnInLoop(func))
no_return_in_loop_.insert(func->result_id());
if (HasNoReturnInLoop(func)) no_return_in_loop_.insert(func->result_id());
}
bool InlinePass::IsInlinableFunction(ir::Function* func) {
// We can only inline a function if it has blocks.
if (func->cbegin() == func->cend())
return false;
if (func->cbegin() == func->cend()) return false;
// Do not inline functions with returns in loops. Currently early return
// functions are inlined by wrapping them in a one trip loop and implementing
// the returns as a branch to the loop's merge block. However, this can only
@ -671,8 +659,7 @@ void InlinePass::InitializeInline(ir::IRContext* c) {
id2block_[blk.id()] = &blk;
}
// Compute inlinability
if (IsInlinableFunction(&fn))
inlinable_.insert(fn.result_id());
if (IsInlinableFunction(&fn)) inlinable_.insert(fn.result_id());
}
};

View File

@ -18,10 +18,10 @@
#define LIBSPIRV_OPT_INLINE_PASS_H_
#include <algorithm>
#include <list>
#include <memory>
#include <unordered_map>
#include <vector>
#include <list>
#include "def_use_manager.h"
#include "module.h"
@ -32,12 +32,11 @@ namespace opt {
// See optimizer.hpp for documentation.
class InlinePass : public Pass {
using cbb_ptr = const ir::BasicBlock*;
public:
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
InlinePass();
virtual ~InlinePass() = default;
@ -54,8 +53,8 @@ class InlinePass : public Pass {
void AddBranch(uint32_t labelId, std::unique_ptr<ir::BasicBlock>* block_ptr);
// Add conditional branch to end of block |block_ptr|.
void AddBranchCond(uint32_t cond_id, uint32_t true_id,
uint32_t false_id, std::unique_ptr<ir::BasicBlock>* block_ptr);
void AddBranchCond(uint32_t cond_id, uint32_t true_id, uint32_t false_id,
std::unique_ptr<ir::BasicBlock>* block_ptr);
// Add unconditional branch to labelId to end of block block_ptr.
void AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
@ -77,8 +76,7 @@ class InlinePass : public Pass {
uint32_t GetFalseId();
// Map callee params to caller args
void MapParams(ir::Function* calleeFn,
ir::BasicBlock::iterator call_inst_itr,
void MapParams(ir::Function* calleeFn, ir::BasicBlock::iterator call_inst_itr,
std::unordered_map<uint32_t, uint32_t>* callee2caller);
// Clone and map callee locals
@ -133,11 +131,11 @@ class InlinePass : public Pass {
// A block's structured successors are the blocks it branches to
// together with its declared merge block if it has one.
// When order matters, the merge block always appears first.
// This assures correct depth first search in the presence of early
// This assures correct depth first search in the presence of early
// returns and kills. If the successor vector contain duplicates
// if the merge block, they are safely ignored by DFS.
void ComputeStructuredSuccessors(ir::Function* func);
// Return function to return ordered structure successors for a given block
// Assumes ComputeStructuredSuccessors() has been called.
GetBlocksFunction StructuredSuccessorsFunction();

View File

@ -16,8 +16,8 @@
#include "insert_extract_elim.h"
#include "iterator.h"
#include "ir_context.h"
#include "iterator.h"
namespace spvtools {
namespace opt {
@ -28,12 +28,11 @@ const uint32_t kExtractCompositeIdInIdx = 0;
const uint32_t kInsertObjectIdInIdx = 0;
const uint32_t kInsertCompositeIdInIdx = 1;
} // anonymous namespace
} // anonymous namespace
bool InsertExtractElimPass::ExtInsMatch(const ir::Instruction* extInst,
const ir::Instruction* insInst) const {
if (extInst->NumInOperands() != insInst->NumInOperands() - 1)
return false;
const ir::Instruction* insInst) const {
if (extInst->NumInOperands() != insInst->NumInOperands() - 1) return false;
uint32_t numIdx = extInst->NumInOperands() - 1;
for (uint32_t i = 0; i < numIdx; ++i)
if (extInst->GetSingleWordInOperand(i + 1) !=
@ -42,10 +41,9 @@ bool InsertExtractElimPass::ExtInsMatch(const ir::Instruction* extInst,
return true;
}
bool InsertExtractElimPass::ExtInsConflict(const ir::Instruction* extInst,
const ir::Instruction* insInst) const {
if (extInst->NumInOperands() == insInst->NumInOperands() - 1)
return false;
bool InsertExtractElimPass::ExtInsConflict(
const ir::Instruction* extInst, const ir::Instruction* insInst) const {
if (extInst->NumInOperands() == insInst->NumInOperands() - 1) return false;
uint32_t extNumIdx = extInst->NumInOperands() - 1;
uint32_t insNumIdx = insInst->NumInOperands() - 2;
uint32_t numIdx = std::min(extNumIdx, insNumIdx);
@ -71,8 +69,7 @@ bool InsertExtractElimPass::EliminateInsertExtract(ir::Function* func) {
ir::Instruction* cinst = get_def_use_mgr()->GetDef(cid);
uint32_t replId = 0;
while (cinst->opcode() == SpvOpCompositeInsert) {
if (ExtInsConflict(&*ii, cinst))
break;
if (ExtInsConflict(&*ii, cinst)) break;
if (ExtInsMatch(&*ii, cinst)) {
replId = cinst->GetSingleWordInOperand(kInsertObjectIdInIdx);
break;
@ -96,14 +93,12 @@ bool InsertExtractElimPass::EliminateInsertExtract(ir::Function* func) {
for (; i <= compIdx; i++) {
uint32_t compId = cinst->GetSingleWordInOperand(i);
ir::Instruction* compInst = get_def_use_mgr()->GetDef(compId);
if (compInst->type_id() != (*ii).type_id())
break;
if (compInst->type_id() != (*ii).type_id()) break;
}
if (i > compIdx)
replId = cinst->GetSingleWordInOperand(compIdx);
}
}
else {
} else {
replId = cinst->GetSingleWordInOperand(compIdx);
}
}
@ -132,8 +127,8 @@ void InsertExtractElimPass::Initialize(ir::IRContext* c) {
bool InsertExtractElimPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : get_module()->extensions()) {
const char* extName = reinterpret_cast<const char*>(
&ei.GetInOperand(0).words[0]);
const char* extName =
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
return false;
}
@ -142,8 +137,7 @@ bool InsertExtractElimPass::AllExtensionsSupported() const {
Pass::Status InsertExtractElimPass::ProcessImpl() {
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process all entry point functions.
ProcessFunction pfn = [this](ir::Function* fp) {
return EliminateInsertExtract(fp);
@ -162,31 +156,30 @@ Pass::Status InsertExtractElimPass::Process(ir::IRContext* c) {
void InsertExtractElimPass::InitExtensions() {
extensions_whitelist_.clear();
extensions_whitelist_.insert({
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
"SPV_KHR_variable_pointers",
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
"SPV_KHR_variable_pointers",
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
});
}
} // namespace opt
} // namespace spvtools

View File

@ -17,7 +17,6 @@
#ifndef LIBSPIRV_OPT_INSERT_EXTRACT_ELIM_PASS_H_
#define LIBSPIRV_OPT_INSERT_EXTRACT_ELIM_PASS_H_
#include <algorithm>
#include <map>
#include <unordered_map>
@ -26,9 +25,9 @@
#include "basic_block.h"
#include "def_use_manager.h"
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {
@ -42,16 +41,16 @@ class InsertExtractElimPass : public Pass {
private:
// Return true if indices of extract |extInst| and insert |insInst| match
bool ExtInsMatch(
const ir::Instruction* extInst, const ir::Instruction* insInst) const;
bool ExtInsMatch(const ir::Instruction* extInst,
const ir::Instruction* insInst) const;
// Return true if indices of extract |extInst| and insert |insInst| conflict,
// specifically, if the insert changes bits specified by the extract, but
// changes either more bits or less bits than the extract specifies,
// meaning the exact value being inserted cannot be used to replace
// the extract.
bool ExtInsConflict(
const ir::Instruction* extInst, const ir::Instruction* insInst) const;
bool ExtInsConflict(const ir::Instruction* extInst,
const ir::Instruction* insInst) const;
// Return true if |typeId| is a vector type
bool IsVectorType(uint32_t typeId);
@ -79,4 +78,3 @@ class InsertExtractElimPass : public Pass {
} // namespace spvtools
#endif // LIBSPIRV_OPT_INSERT_EXTRACT_ELIM_PASS_H_

View File

@ -219,8 +219,8 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
// Runs the given function |f| on all "in" operands
inline void ForEachInOperand(const std::function<void(uint32_t*)>& f);
inline void ForEachInOperand(const std::function<void(const uint32_t*)>& f)
const;
inline void ForEachInOperand(
const std::function<void(const uint32_t*)>& f) const;
// Returns true if any operands can be labels
inline bool HasLabels() const;
@ -308,9 +308,9 @@ inline void Instruction::ForEachInst(
inline void Instruction::ForEachId(const std::function<void(uint32_t*)>& f) {
for (auto& opnd : operands_)
if (spvIsIdType(opnd.type)) f(&opnd.words[0]);
if (type_id_ != 0u)
type_id_ = GetSingleWordOperand(0u);
if (result_id_ != 0u) result_id_ = GetSingleWordOperand(type_id_ == 0u ? 0u : 1u);
if (type_id_ != 0u) type_id_ = GetSingleWordOperand(0u);
if (result_id_ != 0u)
result_id_ = GetSingleWordOperand(type_id_ == 0u ? 0u : 1u);
}
inline void Instruction::ForEachId(
@ -347,7 +347,7 @@ inline void Instruction::ForEachInId(
}
inline void Instruction::ForEachInOperand(
const std::function<void(uint32_t*)>& f) {
const std::function<void(uint32_t*)>& f) {
for (auto& opnd : operands_) {
switch (opnd.type) {
case SPV_OPERAND_TYPE_RESULT_ID:

View File

@ -17,7 +17,6 @@
namespace spvtools {
namespace ir {
InstructionList::iterator InstructionList::iterator::InsertBefore(
std::vector<std::unique_ptr<Instruction>>&& list) {
Instruction* first_node = list.front().get();

View File

@ -24,7 +24,8 @@ void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) {
}
}
void IRContext::InvalidateAnalysesExceptFor(IRContext::Analysis preserved_analyses) {
void IRContext::InvalidateAnalysesExceptFor(
IRContext::Analysis preserved_analyses) {
uint32_t analyses_to_invalidate = valid_analyses_ & (~preserved_analyses);
if (analyses_to_invalidate & kAnalysisDefUse) {
def_use_mgr_.reset(nullptr);
@ -75,7 +76,7 @@ bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
} else if (use.inst->type_id() == 0) {
SPIRV_ASSERT(consumer_, false,
"Result type id considered as use while the instruction "
"doesn't have a result type id.");
"doesn't have a result type id.");
(void)consumer_; // Makes the compiler happy for release build.
} else {
SPIRV_ASSERT(consumer_, false,

View File

@ -123,21 +123,23 @@ class IteratorRange {
// Returns a (begin, end) iterator pair for the given iterators.
// The iterators must belong to the same container.
template<typename IteratorType>
inline IteratorRange<IteratorType> make_range(IteratorType& begin, IteratorType& end) {
template <typename IteratorType>
inline IteratorRange<IteratorType> make_range(IteratorType& begin,
IteratorType& end) {
return {begin, end};
}
// Returns a (begin, end) iterator pair for the given iterators.
// The iterators must belong to the same container.
template<typename IteratorType>
inline IteratorRange<IteratorType> make_range(IteratorType&& begin, IteratorType&& end) {
template <typename IteratorType>
inline IteratorRange<IteratorType> make_range(IteratorType&& begin,
IteratorType&& end) {
return {begin, end};
}
// Returns a (begin, end) iterator pair for the given container.
template<typename ValueType,
class IteratorType = UptrVectorIterator<ValueType>>
template <typename ValueType,
class IteratorType = UptrVectorIterator<ValueType>>
inline IteratorRange<IteratorType> make_range(
std::vector<std::unique_ptr<ValueType>>& container) {
return {IteratorType(&container, container.begin()),

View File

@ -28,7 +28,7 @@ const uint32_t kAccessChainPtrIdInIdx = 0;
const uint32_t kConstantValueInIdx = 0;
const uint32_t kTypeIntWidthInIdx = 0;
} // anonymous namespace
} // anonymous namespace
void LocalAccessChainConvertPass::DeleteIfUseless(ir::Instruction* inst) {
const uint32_t resId = inst->result_id();
@ -40,21 +40,17 @@ void LocalAccessChainConvertPass::DeleteIfUseless(ir::Instruction* inst) {
}
void LocalAccessChainConvertPass::BuildAndAppendInst(
SpvOp opcode,
uint32_t typeId,
uint32_t resultId,
SpvOp opcode, uint32_t typeId, uint32_t resultId,
const std::vector<ir::Operand>& in_opnds,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts) {
std::unique_ptr<ir::Instruction> newInst(new ir::Instruction(
opcode, typeId, resultId, in_opnds));
std::unique_ptr<ir::Instruction> newInst(
new ir::Instruction(opcode, typeId, resultId, in_opnds));
get_def_use_mgr()->AnalyzeInstDefUse(&*newInst);
newInsts->emplace_back(std::move(newInst));
}
uint32_t LocalAccessChainConvertPass::BuildAndAppendVarLoad(
const ir::Instruction* ptrInst,
uint32_t* varId,
uint32_t* varPteTypeId,
const ir::Instruction* ptrInst, uint32_t* varId, uint32_t* varPteTypeId,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts) {
const uint32_t ldResultId = TakeNextId();
*varId = ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx);
@ -62,20 +58,20 @@ uint32_t LocalAccessChainConvertPass::BuildAndAppendVarLoad(
assert(varInst->opcode() == SpvOpVariable);
*varPteTypeId = GetPointeeTypeId(varInst);
BuildAndAppendInst(SpvOpLoad, *varPteTypeId, ldResultId,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {*varId}}}, newInsts);
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {*varId}}},
newInsts);
return ldResultId;
}
void LocalAccessChainConvertPass::AppendConstantOperands(
const ir::Instruction* ptrInst,
std::vector<ir::Operand>* in_opnds) {
const ir::Instruction* ptrInst, std::vector<ir::Operand>* in_opnds) {
uint32_t iidIdx = 0;
ptrInst->ForEachInId([&iidIdx, &in_opnds, this](const uint32_t *iid) {
ptrInst->ForEachInId([&iidIdx, &in_opnds, this](const uint32_t* iid) {
if (iidIdx > 0) {
const ir::Instruction* cInst = get_def_use_mgr()->GetDef(*iid);
uint32_t val = cInst->GetSingleWordInOperand(kConstantValueInIdx);
in_opnds->push_back(
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {val}});
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {val}});
}
++iidIdx;
});
@ -84,12 +80,11 @@ void LocalAccessChainConvertPass::AppendConstantOperands(
uint32_t LocalAccessChainConvertPass::GenAccessChainLoadReplacement(
const ir::Instruction* ptrInst,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts) {
// Build and append load of variable in ptrInst
uint32_t varId;
uint32_t varPteTypeId;
const uint32_t ldResultId = BuildAndAppendVarLoad(ptrInst, &varId,
&varPteTypeId, newInsts);
const uint32_t ldResultId =
BuildAndAppendVarLoad(ptrInst, &varId, &varPteTypeId, newInsts);
// Build and append Extract
const uint32_t extResultId = TakeNextId();
@ -103,30 +98,28 @@ uint32_t LocalAccessChainConvertPass::GenAccessChainLoadReplacement(
}
void LocalAccessChainConvertPass::GenAccessChainStoreReplacement(
const ir::Instruction* ptrInst,
uint32_t valId,
const ir::Instruction* ptrInst, uint32_t valId,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts) {
// Build and append load of variable in ptrInst
uint32_t varId;
uint32_t varPteTypeId;
const uint32_t ldResultId = BuildAndAppendVarLoad(ptrInst, &varId,
&varPteTypeId, newInsts);
const uint32_t ldResultId =
BuildAndAppendVarLoad(ptrInst, &varId, &varPteTypeId, newInsts);
// Build and append Insert
const uint32_t insResultId = TakeNextId();
std::vector<ir::Operand> ins_in_opnds =
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {valId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ldResultId}}};
std::vector<ir::Operand> ins_in_opnds = {
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {valId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ldResultId}}};
AppendConstantOperands(ptrInst, &ins_in_opnds);
BuildAndAppendInst(
SpvOpCompositeInsert, varPteTypeId, insResultId, ins_in_opnds, newInsts);
BuildAndAppendInst(SpvOpCompositeInsert, varPteTypeId, insResultId,
ins_in_opnds, newInsts);
// Build and append Store
BuildAndAppendInst(SpvOpStore, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {varId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {insResultId}}},
newInsts);
BuildAndAppendInst(SpvOpStore, 0, 0,
{{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {varId}},
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {insResultId}}},
newInsts);
}
bool LocalAccessChainConvertPass::IsConstantIndexAccessChain(
@ -144,8 +137,7 @@ bool LocalAccessChainConvertPass::IsConstantIndexAccessChain(
}
bool LocalAccessChainConvertPass::HasOnlySupportedRefs(uint32_t ptrId) {
if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end())
return true;
if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end()) return true;
analysis::UseList* uses = get_def_use_mgr()->GetUses(ptrId);
assert(uses != nullptr);
for (auto u : *uses) {
@ -164,36 +156,36 @@ void LocalAccessChainConvertPass::FindTargetVars(ir::Function* func) {
for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
switch (ii->opcode()) {
case SpvOpStore:
case SpvOpLoad: {
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsTargetVar(varId))
case SpvOpStore:
case SpvOpLoad: {
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsTargetVar(varId)) break;
const SpvOp op = ptrInst->opcode();
// Rule out variables with non-supported refs eg function calls
if (!HasOnlySupportedRefs(varId)) {
seen_non_target_vars_.insert(varId);
seen_target_vars_.erase(varId);
break;
}
// Rule out variables with nested access chains
// TODO(): Convert nested access chains
if (IsNonPtrAccessChain(op) &&
ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx) !=
varId) {
seen_non_target_vars_.insert(varId);
seen_target_vars_.erase(varId);
break;
}
// Rule out variables accessed with non-constant indices
if (!IsConstantIndexAccessChain(ptrInst)) {
seen_non_target_vars_.insert(varId);
seen_target_vars_.erase(varId);
break;
}
} break;
default:
break;
const SpvOp op = ptrInst->opcode();
// Rule out variables with non-supported refs eg function calls
if (!HasOnlySupportedRefs(varId)) {
seen_non_target_vars_.insert(varId);
seen_target_vars_.erase(varId);
break;
}
// Rule out variables with nested access chains
// TODO(): Convert nested access chains
if (IsNonPtrAccessChain(op) &&
ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx) != varId) {
seen_non_target_vars_.insert(varId);
seen_target_vars_.erase(varId);
break;
}
// Rule out variables accessed with non-constant indices
if (!IsConstantIndexAccessChain(ptrInst)) {
seen_non_target_vars_.insert(varId);
seen_target_vars_.erase(varId);
break;
}
} break;
default:
break;
}
}
}
@ -207,42 +199,37 @@ bool LocalAccessChainConvertPass::ConvertLocalAccessChains(ir::Function* func) {
for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
switch (ii->opcode()) {
case SpvOpLoad: {
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsNonPtrAccessChain(ptrInst->opcode()))
case SpvOpLoad: {
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsNonPtrAccessChain(ptrInst->opcode())) break;
if (!IsTargetVar(varId)) break;
std::vector<std::unique_ptr<ir::Instruction>> newInsts;
uint32_t replId = GenAccessChainLoadReplacement(ptrInst, &newInsts);
ReplaceAndDeleteLoad(&*ii, replId);
++ii;
ii = ii.InsertBefore(std::move(newInsts));
++ii;
modified = true;
} break;
case SpvOpStore: {
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsNonPtrAccessChain(ptrInst->opcode())) break;
if (!IsTargetVar(varId)) break;
std::vector<std::unique_ptr<ir::Instruction>> newInsts;
uint32_t valId = ii->GetSingleWordInOperand(kStoreValIdInIdx);
GenAccessChainStoreReplacement(ptrInst, valId, &newInsts);
context()->KillInst(&*ii);
DeleteIfUseless(ptrInst);
++ii;
ii = ii.InsertBefore(std::move(newInsts));
++ii;
++ii;
modified = true;
} break;
default:
break;
if (!IsTargetVar(varId))
break;
std::vector<std::unique_ptr<ir::Instruction>> newInsts;
uint32_t replId =
GenAccessChainLoadReplacement(ptrInst, &newInsts);
ReplaceAndDeleteLoad(&*ii, replId);
++ii;
ii = ii.InsertBefore(std::move(newInsts));
++ii;
modified = true;
} break;
case SpvOpStore: {
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsNonPtrAccessChain(ptrInst->opcode()))
break;
if (!IsTargetVar(varId))
break;
std::vector<std::unique_ptr<ir::Instruction>> newInsts;
uint32_t valId = ii->GetSingleWordInOperand(kStoreValIdInIdx);
GenAccessChainStoreReplacement(ptrInst, valId, &newInsts);
context()->KillInst(&*ii);
DeleteIfUseless(ptrInst);
++ii;
ii = ii.InsertBefore(std::move(newInsts));
++ii;
++ii;
modified = true;
} break;
default:
break;
}
}
}
@ -266,8 +253,8 @@ void LocalAccessChainConvertPass::Initialize(ir::IRContext* c) {
bool LocalAccessChainConvertPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : get_module()->extensions()) {
const char* extName = reinterpret_cast<const char*>(
&ei.GetInOperand(0).words[0]);
const char* extName =
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
return false;
}
@ -285,11 +272,9 @@ Pass::Status LocalAccessChainConvertPass::ProcessImpl() {
// support required in KillNamesAndDecorates().
// TODO(greg-lunarg): Add support for OpGroupDecorate
for (auto& ai : get_module()->annotations())
if (ai.opcode() == SpvOpGroupDecorate)
return Status::SuccessWithoutChange;
if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange;
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process all entry point functions.
ProcessFunction pfn = [this](ir::Function* fp) {
return ConvertLocalAccessChains(fp);
@ -308,32 +293,22 @@ Pass::Status LocalAccessChainConvertPass::Process(ir::IRContext* c) {
void LocalAccessChainConvertPass::InitExtensions() {
extensions_whitelist_.clear();
extensions_whitelist_.insert({
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
// SPV_KHR_variable_pointers
// Currently do not support extended pointer expressions
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot", "SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float", "SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote", "SPV_KHR_16bit_storage", "SPV_KHR_device_group",
"SPV_KHR_multiview", "SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2", "SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough", "SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
// SPV_KHR_variable_pointers
// Currently do not support extended pointer expressions
"SPV_AMD_gpu_shader_int16", "SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
});
}
} // namespace opt
} // namespace spvtools

View File

@ -17,7 +17,6 @@
#ifndef LIBSPIRV_OPT_LOCAL_ACCESS_CHAIN_CONVERT_PASS_H_
#define LIBSPIRV_OPT_LOCAL_ACCESS_CHAIN_CONVERT_PASS_H_
#include <algorithm>
#include <map>
#include <queue>
@ -27,8 +26,8 @@
#include "basic_block.h"
#include "def_use_manager.h"
#include "module.h"
#include "mem_pass.h"
#include "module.h"
namespace spvtools {
namespace opt {
@ -59,38 +58,40 @@ class LocalAccessChainConvertPass : public MemPass {
// Build instruction from |opcode|, |typeId|, |resultId|, and |in_opnds|.
// Append to |newInsts|.
void BuildAndAppendInst(SpvOp opcode, uint32_t typeId, uint32_t resultId,
const std::vector<ir::Operand>& in_opnds,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts);
void BuildAndAppendInst(
SpvOp opcode, uint32_t typeId, uint32_t resultId,
const std::vector<ir::Operand>& in_opnds,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts);
// Build load of variable in |ptrInst| and append to |newInsts|.
// Return var in |varId| and its pointee type in |varPteTypeId|.
uint32_t BuildAndAppendVarLoad(const ir::Instruction* ptrInst,
uint32_t* varId, uint32_t* varPteTypeId,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts);
uint32_t BuildAndAppendVarLoad(
const ir::Instruction* ptrInst, uint32_t* varId, uint32_t* varPteTypeId,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts);
// Append literal integer operands to |in_opnds| corresponding to constant
// integer operands from access chain |ptrInst|. Assumes all indices in
// access chains are OpConstant.
void AppendConstantOperands( const ir::Instruction* ptrInst,
std::vector<ir::Operand>* in_opnds);
void AppendConstantOperands(const ir::Instruction* ptrInst,
std::vector<ir::Operand>* in_opnds);
// Create a load/insert/store equivalent to a store of
// |valId| through (constant index) access chaing |ptrInst|.
// Append to |newInsts|.
void GenAccessChainStoreReplacement(const ir::Instruction* ptrInst,
uint32_t valId,
void GenAccessChainStoreReplacement(
const ir::Instruction* ptrInst, uint32_t valId,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts);
// For the (constant index) access chain |ptrInst|, create an
// equivalent load and extract. Append to |newInsts|.
uint32_t GenAccessChainLoadReplacement(const ir::Instruction* ptrInst,
uint32_t GenAccessChainLoadReplacement(
const ir::Instruction* ptrInst,
std::vector<std::unique_ptr<ir::Instruction>>* newInsts);
// Return true if all indices of access chain |acp| are OpConstant integers
bool IsConstantIndexAccessChain(const ir::Instruction* acp) const;
// Identify all function scope variables of target type which are
// Identify all function scope variables of target type which are
// accessed only with loads, stores and access chains with constant
// indices. Convert all loads and stores of such variables into equivalent
// loads, stores, extracts and inserts. This unifies access to these
@ -122,4 +123,3 @@ class LocalAccessChainConvertPass : public MemPass {
} // namespace spvtools
#endif // LIBSPIRV_OPT_LOCAL_ACCESS_CHAIN_CONVERT_PASS_H_

View File

@ -25,11 +25,10 @@ namespace {
const uint32_t kStoreValIdInIdx = 1;
} // anonymous namespace
} // anonymous namespace
bool LocalSingleBlockLoadStoreElimPass::HasOnlySupportedRefs(uint32_t ptrId) {
if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end())
return true;
if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end()) return true;
analysis::UseList* uses = get_def_use_mgr()->GetUses(ptrId);
assert(uses != nullptr);
for (auto u : *uses) {
@ -54,83 +53,74 @@ bool LocalSingleBlockLoadStoreElimPass::LocalSingleBlockLoadStoreElim(
pinned_vars_.clear();
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
switch (ii->opcode()) {
case SpvOpStore: {
// Verify store variable is target type
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsTargetVar(varId))
continue;
if (!HasOnlySupportedRefs(varId))
continue;
// Register the store
if (ptrInst->opcode() == SpvOpVariable) {
// if not pinned, look for WAW
if (pinned_vars_.find(varId) == pinned_vars_.end()) {
case SpvOpStore: {
// Verify store variable is target type
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsTargetVar(varId)) continue;
if (!HasOnlySupportedRefs(varId)) continue;
// Register the store
if (ptrInst->opcode() == SpvOpVariable) {
// if not pinned, look for WAW
if (pinned_vars_.find(varId) == pinned_vars_.end()) {
auto si = var2store_.find(varId);
if (si != var2store_.end()) {
context()->KillInst(si->second);
}
}
var2store_[varId] = &*ii;
} else {
assert(IsNonPtrAccessChain(ptrInst->opcode()));
var2store_.erase(varId);
}
pinned_vars_.erase(varId);
var2load_.erase(varId);
} break;
case SpvOpLoad: {
// Verify store variable is target type
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsTargetVar(varId)) continue;
if (!HasOnlySupportedRefs(varId)) continue;
// Look for previous store or load
uint32_t replId = 0;
if (ptrInst->opcode() == SpvOpVariable) {
auto si = var2store_.find(varId);
if (si != var2store_.end()) {
context()->KillInst(si->second);
replId = si->second->GetSingleWordInOperand(kStoreValIdInIdx);
} else {
auto li = var2load_.find(varId);
if (li != var2load_.end()) {
replId = li->second->result_id();
}
}
}
var2store_[varId] = &*ii;
}
else {
assert(IsNonPtrAccessChain(ptrInst->opcode()));
var2store_.erase(varId);
}
pinned_vars_.erase(varId);
var2load_.erase(varId);
} break;
case SpvOpLoad: {
// Verify store variable is target type
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (!IsTargetVar(varId))
continue;
if (!HasOnlySupportedRefs(varId))
continue;
// Look for previous store or load
uint32_t replId = 0;
if (ptrInst->opcode() == SpvOpVariable) {
auto si = var2store_.find(varId);
if (si != var2store_.end()) {
replId = si->second->GetSingleWordInOperand(kStoreValIdInIdx);
if (replId != 0) {
// replace load's result id and delete load
ReplaceAndDeleteLoad(&*ii, replId);
modified = true;
} else {
if (ptrInst->opcode() == SpvOpVariable)
var2load_[varId] = &*ii; // register load
pinned_vars_.insert(varId);
}
else {
auto li = var2load_.find(varId);
if (li != var2load_.end()) {
replId = li->second->result_id();
}
}
}
if (replId != 0) {
// replace load's result id and delete load
ReplaceAndDeleteLoad(&*ii, replId);
modified = true;
}
else {
if (ptrInst->opcode() == SpvOpVariable)
var2load_[varId] = &*ii; // register load
pinned_vars_.insert(varId);
}
} break;
case SpvOpFunctionCall: {
// Conservatively assume all locals are redefined for now.
// TODO(): Handle more optimally
var2store_.clear();
var2load_.clear();
pinned_vars_.clear();
} break;
default:
break;
} break;
case SpvOpFunctionCall: {
// Conservatively assume all locals are redefined for now.
// TODO(): Handle more optimally
var2store_.clear();
var2load_.clear();
pinned_vars_.clear();
} break;
default:
break;
}
}
// Go back and delete useless stores in block
// TODO(greg-lunarg): Consider moving DCE into separate pass
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
if (ii->opcode() != SpvOpStore)
continue;
if (IsLiveStore(&*ii))
continue;
if (ii->opcode() != SpvOpStore) continue;
if (IsLiveStore(&*ii)) continue;
DCEInst(&*ii);
}
}
@ -154,8 +144,8 @@ void LocalSingleBlockLoadStoreElimPass::Initialize(ir::IRContext* c) {
bool LocalSingleBlockLoadStoreElimPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : get_module()->extensions()) {
const char* extName = reinterpret_cast<const char*>(
&ei.GetInOperand(0).words[0]);
const char* extName =
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
return false;
}
@ -170,12 +160,10 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::ProcessImpl() {
// support required in KillNamesAndDecorates().
// TODO(greg-lunarg): Add support for OpGroupDecorate
for (auto& ai : get_module()->annotations())
if (ai.opcode() == SpvOpGroupDecorate)
return Status::SuccessWithoutChange;
if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange;
// If any extensions in the module are not explicitly supported,
// return unmodified.
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
// return unmodified.
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process all entry point functions
ProcessFunction pfn = [this](ir::Function* fp) {
return LocalSingleBlockLoadStoreElim(fp);
@ -194,29 +182,20 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::Process(ir::IRContext* c) {
void LocalSingleBlockLoadStoreElimPass::InitExtensions() {
extensions_whitelist_.clear();
extensions_whitelist_.insert({
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
// SPV_KHR_variable_pointers
// Currently do not support extended pointer expressions
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot", "SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float", "SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote", "SPV_KHR_16bit_storage", "SPV_KHR_device_group",
"SPV_KHR_multiview", "SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2", "SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough", "SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
// SPV_KHR_variable_pointers
// Currently do not support extended pointer expressions
"SPV_AMD_gpu_shader_int16", "SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
});
}

View File

@ -17,18 +17,17 @@
#ifndef LIBSPIRV_OPT_LOCAL_SINGLE_BLOCK_ELIM_PASS_H_
#define LIBSPIRV_OPT_LOCAL_SINGLE_BLOCK_ELIM_PASS_H_
#include <algorithm>
#include <map>
#include <queue>
#include <utility>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include "basic_block.h"
#include "def_use_manager.h"
#include "module.h"
#include "mem_pass.h"
#include "module.h"
namespace spvtools {
namespace opt {
@ -98,4 +97,3 @@ class LocalSingleBlockLoadStoreElimPass : public MemPass {
} // namespace spvtools
#endif // LIBSPIRV_OPT_LOCAL_SINGLE_BLOCK_ELIM_PASS_H_

View File

@ -27,11 +27,10 @@ namespace {
const uint32_t kStoreValIdInIdx = 1;
} // anonymous namespace
} // anonymous namespace
bool LocalSingleStoreElimPass::HasOnlySupportedRefs(uint32_t ptrId) {
if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end())
return true;
if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end()) return true;
analysis::UseList* uses = get_def_use_mgr()->GetUses(ptrId);
assert(uses != nullptr);
for (auto u : *uses) {
@ -55,41 +54,40 @@ void LocalSingleStoreElimPass::SingleStoreAnalyze(ir::Function* func) {
uint32_t instIdx = 0;
for (auto ii = bi->begin(); ii != bi->end(); ++ii, ++instIdx) {
switch (ii->opcode()) {
case SpvOpStore: {
// Verify store variable is target type
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (non_ssa_vars_.find(varId) != non_ssa_vars_.end())
continue;
if (ptrInst->opcode() != SpvOpVariable) {
non_ssa_vars_.insert(varId);
ssa_var2store_.erase(varId);
continue;
}
// Verify target type and function storage class
if (!IsTargetVar(varId)) {
non_ssa_vars_.insert(varId);
continue;
}
if (!HasOnlySupportedRefs(varId)) {
non_ssa_vars_.insert(varId);
continue;
}
// Ignore variables with multiple stores
if (ssa_var2store_.find(varId) != ssa_var2store_.end()) {
non_ssa_vars_.insert(varId);
ssa_var2store_.erase(varId);
continue;
}
// Remember pointer to variable's store and it's
// ordinal position in block
ssa_var2store_[varId] = &*ii;
store2idx_[&*ii] = instIdx;
store2blk_[&*ii] = &*bi;
} break;
default:
break;
} // switch
case SpvOpStore: {
// Verify store variable is target type
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
if (non_ssa_vars_.find(varId) != non_ssa_vars_.end()) continue;
if (ptrInst->opcode() != SpvOpVariable) {
non_ssa_vars_.insert(varId);
ssa_var2store_.erase(varId);
continue;
}
// Verify target type and function storage class
if (!IsTargetVar(varId)) {
non_ssa_vars_.insert(varId);
continue;
}
if (!HasOnlySupportedRefs(varId)) {
non_ssa_vars_.insert(varId);
continue;
}
// Ignore variables with multiple stores
if (ssa_var2store_.find(varId) != ssa_var2store_.end()) {
non_ssa_vars_.insert(varId);
ssa_var2store_.erase(varId);
continue;
}
// Remember pointer to variable's store and it's
// ordinal position in block
ssa_var2store_[varId] = &*ii;
store2idx_[&*ii] = instIdx;
store2blk_[&*ii] = &*bi;
} break;
default:
break;
} // switch
}
}
}
@ -98,8 +96,7 @@ LocalSingleStoreElimPass::GetBlocksFunction
LocalSingleStoreElimPass::AugmentedCFGSuccessorsFunction() const {
return [this](const ir::BasicBlock* block) {
auto asmi = augmented_successors_map_.find(block);
if (asmi != augmented_successors_map_.end())
return &(*asmi).second;
if (asmi != augmented_successors_map_.end()) return &(*asmi).second;
auto smi = successors_map_.find(block);
return &(*smi).second;
};
@ -109,8 +106,7 @@ LocalSingleStoreElimPass::GetBlocksFunction
LocalSingleStoreElimPass::AugmentedCFGPredecessorsFunction() const {
return [this](const ir::BasicBlock* block) {
auto apmi = augmented_predecessors_map_.find(block);
if (apmi != augmented_predecessors_map_.end())
return &(*apmi).second;
if (apmi != augmented_predecessors_map_.end()) return &(*apmi).second;
auto pmi = predecessors_map_.find(block);
return &(*pmi).second;
};
@ -134,43 +130,36 @@ void LocalSingleStoreElimPass::CalculateImmediateDominators(
augmented_predecessors_map_.clear();
successors_map_[cfg()->pseudo_exit_block()] = {};
predecessors_map_[cfg()->pseudo_entry_block()] = {};
auto succ_func = [this](const ir::BasicBlock* b)
{ return &successors_map_[b]; };
auto pred_func = [this](const ir::BasicBlock* b)
{ return &predecessors_map_[b]; };
auto succ_func = [this](const ir::BasicBlock* b) {
return &successors_map_[b];
};
auto pred_func = [this](const ir::BasicBlock* b) {
return &predecessors_map_[b];
};
CFA<ir::BasicBlock>::ComputeAugmentedCFG(
ordered_blocks,
cfg()->pseudo_entry_block(),
cfg()->pseudo_exit_block(),
&augmented_successors_map_,
&augmented_predecessors_map_,
succ_func,
pred_func);
ordered_blocks, cfg()->pseudo_entry_block(), cfg()->pseudo_exit_block(),
&augmented_successors_map_, &augmented_predecessors_map_, succ_func,
pred_func);
// Compute Dominators
vector<const ir::BasicBlock*> postorder;
auto ignore_block = [](cbb_ptr) {};
auto ignore_edge = [](cbb_ptr, cbb_ptr) {};
spvtools::CFA<ir::BasicBlock>::DepthFirstTraversal(
ordered_blocks[0], AugmentedCFGSuccessorsFunction(),
ignore_block, [&](cbb_ptr b) { postorder.push_back(b); },
ignore_edge);
ordered_blocks[0], AugmentedCFGSuccessorsFunction(), ignore_block,
[&](cbb_ptr b) { postorder.push_back(b); }, ignore_edge);
auto edges = spvtools::CFA<ir::BasicBlock>::CalculateDominators(
postorder, AugmentedCFGPredecessorsFunction());
postorder, AugmentedCFGPredecessorsFunction());
idom_.clear();
for (auto edge : edges)
idom_[edge.first] = edge.second;
for (auto edge : edges) idom_[edge.first] = edge.second;
}
bool LocalSingleStoreElimPass::Dominates(
ir::BasicBlock* blk0, uint32_t idx0,
ir::BasicBlock* blk1, uint32_t idx1) {
if (blk0 == blk1)
return idx0 <= idx1;
bool LocalSingleStoreElimPass::Dominates(ir::BasicBlock* blk0, uint32_t idx0,
ir::BasicBlock* blk1, uint32_t idx1) {
if (blk0 == blk1) return idx0 <= idx1;
ir::BasicBlock* b = blk1;
while (idom_[b] != b) {
b = idom_[b];
if (b == blk0)
return true;
if (b == blk0) return true;
}
return false;
}
@ -181,20 +170,17 @@ bool LocalSingleStoreElimPass::SingleStoreProcess(ir::Function* func) {
for (auto bi = func->begin(); bi != func->end(); ++bi) {
uint32_t instIdx = 0;
for (auto ii = bi->begin(); ii != bi->end(); ++ii, ++instIdx) {
if (ii->opcode() != SpvOpLoad)
continue;
if (ii->opcode() != SpvOpLoad) continue;
uint32_t varId;
ir::Instruction* ptrInst = GetPtr(&*ii, &varId);
// Skip access chain loads
if (ptrInst->opcode() != SpvOpVariable)
continue;
if (ptrInst->opcode() != SpvOpVariable) continue;
const auto vsi = ssa_var2store_.find(varId);
if (vsi == ssa_var2store_.end())
continue;
if (non_ssa_vars_.find(varId) != non_ssa_vars_.end())
continue;
if (vsi == ssa_var2store_.end()) continue;
if (non_ssa_vars_.find(varId) != non_ssa_vars_.end()) continue;
// store must dominate load
if (!Dominates(store2blk_[vsi->second], store2idx_[vsi->second], &*bi, instIdx))
if (!Dominates(store2blk_[vsi->second], store2idx_[vsi->second], &*bi,
instIdx))
continue;
// Use store value as replacement id
uint32_t replId = vsi->second->GetSingleWordInOperand(kStoreValIdInIdx);
@ -210,10 +196,8 @@ bool LocalSingleStoreElimPass::SingleStoreDCE() {
bool modified = false;
for (auto v : ssa_var2store_) {
// check that it hasn't already been DCE'd
if (v.second->opcode() != SpvOpStore)
continue;
if (non_ssa_vars_.find(v.first) != non_ssa_vars_.end())
continue;
if (v.second->opcode() != SpvOpStore) continue;
if (non_ssa_vars_.find(v.first) != non_ssa_vars_.end()) continue;
if (!IsLiveStore(v.second)) {
DCEInst(v.second);
modified = true;
@ -225,8 +209,7 @@ bool LocalSingleStoreElimPass::SingleStoreDCE() {
bool LocalSingleStoreElimPass::LocalSingleStoreElim(ir::Function* func) {
bool modified = false;
SingleStoreAnalyze(func);
if (ssa_var2store_.empty())
return false;
if (ssa_var2store_.empty()) return false;
modified |= SingleStoreProcess(func);
modified |= SingleStoreDCE();
return modified;
@ -258,8 +241,8 @@ void LocalSingleStoreElimPass::Initialize(ir::IRContext* irContext) {
bool LocalSingleStoreElimPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : get_module()->extensions()) {
const char* extName = reinterpret_cast<const char*>(
&ei.GetInOperand(0).words[0]);
const char* extName =
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
return false;
}
@ -274,11 +257,9 @@ Pass::Status LocalSingleStoreElimPass::ProcessImpl() {
// support required in KillNamesAndDecorates().
// TODO(greg-lunarg): Add support for OpGroupDecorate
for (auto& ai : get_module()->annotations())
if (ai.opcode() == SpvOpGroupDecorate)
return Status::SuccessWithoutChange;
if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange;
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process all entry point functions
ProcessFunction pfn = [this](ir::Function* fp) {
return LocalSingleStoreElim(fp);
@ -297,29 +278,20 @@ Pass::Status LocalSingleStoreElimPass::Process(ir::IRContext* irContext) {
void LocalSingleStoreElimPass::InitExtensions() {
extensions_whitelist_.clear();
extensions_whitelist_.insert({
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
// SPV_KHR_variable_pointers
// Currently do not support extended pointer expressions
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot", "SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float", "SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote", "SPV_KHR_16bit_storage", "SPV_KHR_device_group",
"SPV_KHR_multiview", "SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2", "SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough", "SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
// SPV_KHR_variable_pointers
// Currently do not support extended pointer expressions
"SPV_AMD_gpu_shader_int16", "SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
});
}

View File

@ -17,7 +17,6 @@
#ifndef LIBSPIRV_OPT_LOCAL_SINGLE_STORE_ELIM_PASS_H_
#define LIBSPIRV_OPT_LOCAL_SINGLE_STORE_ELIM_PASS_H_
#include <algorithm>
#include <map>
#include <queue>
@ -27,8 +26,8 @@
#include "basic_block.h"
#include "def_use_manager.h"
#include "module.h"
#include "mem_pass.h"
#include "module.h"
namespace spvtools {
namespace opt {
@ -58,7 +57,7 @@ class LocalSingleStoreElimPass : public MemPass {
void SingleStoreAnalyze(ir::Function* func);
using GetBlocksFunction =
std::function<const std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
std::function<const std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
/// Returns the block successors function for the augmented CFG.
GetBlocksFunction AugmentedCFGSuccessorsFunction() const;
@ -70,11 +69,11 @@ class LocalSingleStoreElimPass : public MemPass {
// in idom_. Entries for augmented CFG (pseudo blocks) are not created.
// TODO(dnovillo): Move to new CFG class.
void CalculateImmediateDominators(ir::Function* func);
// Return true if instruction in |blk0| at ordinal position |idx0|
// dominates instruction in |blk1| at position |idx1|.
bool Dominates(ir::BasicBlock* blk0, uint32_t idx0,
ir::BasicBlock* blk1, uint32_t idx1);
bool Dominates(ir::BasicBlock* blk0, uint32_t idx0, ir::BasicBlock* blk1,
uint32_t idx1);
// For each load of an SSA variable in |func|, replace all uses of
// the load with the value stored if the store dominates the load.
@ -123,19 +122,19 @@ class LocalSingleStoreElimPass : public MemPass {
// CFG Predecessors
std::unordered_map<const ir::BasicBlock*, std::vector<ir::BasicBlock*>>
predecessors_map_;
predecessors_map_;
// CFG Successors
std::unordered_map<const ir::BasicBlock*, std::vector<ir::BasicBlock*>>
successors_map_;
successors_map_;
// CFG Augmented Predecessors
std::unordered_map<const ir::BasicBlock*, std::vector<ir::BasicBlock*>>
augmented_predecessors_map_;
augmented_predecessors_map_;
// CFG Augmented Successors
std::unordered_map<const ir::BasicBlock*, std::vector<ir::BasicBlock*>>
augmented_successors_map_;
augmented_successors_map_;
// Immediate Dominator Map
// If block has no idom it points to itself.
@ -149,4 +148,3 @@ class LocalSingleStoreElimPass : public MemPass {
} // namespace spvtools
#endif // LIBSPIRV_OPT_LOCAL_SINGLE_STORE_ELIM_PASS_H_

View File

@ -16,27 +16,24 @@
#include "local_ssa_elim_pass.h"
#include "iterator.h"
#include "cfa.h"
#include "iterator.h"
namespace spvtools {
namespace opt {
bool LocalMultiStoreElimPass::EliminateMultiStoreLocal(ir::Function* func) {
// Add Phi instructions to the function.
if (InsertPhiInstructions(func) == Status::SuccessWithoutChange)
return false;
if (InsertPhiInstructions(func) == Status::SuccessWithoutChange) return false;
// Remove all target variable stores.
bool modified = false;
for (auto bi = func->begin(); bi != func->end(); ++bi) {
for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
if (ii->opcode() != SpvOpStore)
continue;
if (ii->opcode() != SpvOpStore) continue;
uint32_t varId;
(void) GetPtr(&*ii, &varId);
if (!IsTargetVar(varId))
continue;
(void)GetPtr(&*ii, &varId);
if (!IsTargetVar(varId)) continue;
assert(!HasLoads(varId));
DCEInst(&*ii);
modified = true;
@ -56,8 +53,8 @@ void LocalMultiStoreElimPass::Initialize(ir::IRContext* c) {
bool LocalMultiStoreElimPass::AllExtensionsSupported() const {
// If any extension not in whitelist, return false
for (auto& ei : get_module()->extensions()) {
const char* extName = reinterpret_cast<const char*>(
&ei.GetInOperand(0).words[0]);
const char* extName =
reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
return false;
}
@ -76,12 +73,10 @@ Pass::Status LocalMultiStoreElimPass::ProcessImpl() {
// Do not process if module contains OpGroupDecorate. Additional
// support required in KillNamesAndDecorates().
// TODO(greg-lunarg): Add support for OpGroupDecorate
for (auto& ai : get_module()->annotations())
if (ai.opcode() == SpvOpGroupDecorate)
return Status::SuccessWithoutChange;
for (auto& ai : get_module()->annotations())
if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange;
// Do not process if any disallowed extensions are enabled
if (!AllExtensionsSupported())
return Status::SuccessWithoutChange;
if (!AllExtensionsSupported()) return Status::SuccessWithoutChange;
// Process functions
ProcessFunction pfn = [this](ir::Function* fp) {
return EliminateMultiStoreLocal(fp);
@ -100,32 +95,22 @@ Pass::Status LocalMultiStoreElimPass::Process(ir::IRContext* c) {
void LocalMultiStoreElimPass::InitExtensions() {
extensions_whitelist_.clear();
extensions_whitelist_.insert({
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax",
"SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot",
"SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float",
"SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote",
"SPV_KHR_16bit_storage",
"SPV_KHR_device_group",
"SPV_KHR_multiview",
"SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2",
"SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough",
"SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
// SPV_KHR_variable_pointers
// Currently do not support extended pointer expressions
"SPV_AMD_gpu_shader_int16",
"SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
"SPV_AMD_shader_explicit_vertex_parameter",
"SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader",
"SPV_KHR_shader_ballot", "SPV_AMD_shader_ballot",
"SPV_AMD_gpu_shader_half_float", "SPV_KHR_shader_draw_parameters",
"SPV_KHR_subgroup_vote", "SPV_KHR_16bit_storage", "SPV_KHR_device_group",
"SPV_KHR_multiview", "SPV_NVX_multiview_per_view_attributes",
"SPV_NV_viewport_array2", "SPV_NV_stereo_view_rendering",
"SPV_NV_sample_mask_override_coverage",
"SPV_NV_geometry_shader_passthrough", "SPV_AMD_texture_gather_bias_lod",
"SPV_KHR_storage_buffer_storage_class",
// SPV_KHR_variable_pointers
// Currently do not support extended pointer expressions
"SPV_AMD_gpu_shader_int16", "SPV_KHR_post_depth_coverage",
"SPV_KHR_shader_atomic_counter_ops",
});
}
} // namespace opt
} // namespace spvtools

View File

@ -17,18 +17,17 @@
#ifndef LIBSPIRV_OPT_LOCAL_SSA_ELIM_PASS_H_
#define LIBSPIRV_OPT_LOCAL_SSA_ELIM_PASS_H_
#include <algorithm>
#include <map>
#include <queue>
#include <utility>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include "basic_block.h"
#include "def_use_manager.h"
#include "module.h"
#include "mem_pass.h"
#include "module.h"
namespace spvtools {
namespace opt {
@ -38,8 +37,8 @@ class LocalMultiStoreElimPass : public MemPass {
using cbb_ptr = const ir::BasicBlock*;
public:
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
using GetBlocksFunction =
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
LocalMultiStoreElimPass();
const char* name() const override { return "eliminate-local-multi-store"; }
@ -70,4 +69,3 @@ class LocalMultiStoreElimPass : public MemPass {
} // namespace spvtools
#endif // LIBSPIRV_OPT_LOCAL_SSA_ELIM_PASS_H_

View File

@ -626,7 +626,8 @@ Pass::Status MemPass::InsertPhiInstructions(ir::Function* func) {
}
// If variable is not defined, use undef
if (replId == 0) {
replId = Type2Undef(GetPointeeTypeId(get_def_use_mgr()->GetDef(varId)));
replId =
Type2Undef(GetPointeeTypeId(get_def_use_mgr()->GetDef(varId)));
}
// Replace load's id with the last stored value id for variable
// and delete load. Kill any names or decorates using id before
@ -720,7 +721,7 @@ void MemPass::RemovePhiOperands(
assert(i % 2 == 0 && i < phi->NumOperands() - 1 &&
"malformed Phi arguments");
ir::BasicBlock *in_block = cfg()->block(phi->GetSingleWordOperand(i + 1));
ir::BasicBlock* in_block = cfg()->block(phi->GetSingleWordOperand(i + 1));
if (reachable_blocks.find(in_block) == reachable_blocks.end()) {
// If the incoming block is unreachable, remove both operands as this
// means that the |phi| has lost an incoming edge.
@ -730,7 +731,7 @@ void MemPass::RemovePhiOperands(
// In all other cases, the operand must be kept but may need to be changed.
uint32_t arg_id = phi->GetSingleWordOperand(i);
ir::BasicBlock *def_block = def_block_[arg_id];
ir::BasicBlock* def_block = def_block_[arg_id];
if (def_block &&
reachable_blocks.find(def_block_[arg_id]) == reachable_blocks.end()) {
// If the current |phi| argument was defined in an unreachable block, it
@ -824,10 +825,8 @@ bool MemPass::RemoveUnreachableBlocks(ir::Function* func) {
// If the block is reachable and has Phi instructions, remove all
// operands from its Phi instructions that reference unreachable blocks.
// If the block has no Phi instructions, this is a no-op.
block.ForEachPhiInst(
[&block, &reachable_blocks, this](ir::Instruction* phi) {
RemovePhiOperands(phi, reachable_blocks);
});
block.ForEachPhiInst([&block, &reachable_blocks, this](
ir::Instruction* phi) { RemovePhiOperands(phi, reachable_blocks); });
}
// Erase unreachable blocks.
@ -869,4 +868,3 @@ void MemPass::InitializeCFGCleanup(ir::IRContext* c) {
} // namespace opt
} // namespace spvtools

View File

@ -242,4 +242,3 @@ class MemPass : public Pass {
} // namespace spvtools
#endif // LIBSPIRV_OPT_OPT_PASS_H_

View File

@ -323,7 +323,7 @@ inline IteratorRange<Module::inst_iterator> Module::ext_inst_imports() {
}
inline IteratorRange<Module::const_inst_iterator> Module::ext_inst_imports()
const {
const {
return make_range(ext_inst_imports_.begin(), ext_inst_imports_.end());
}
@ -380,7 +380,7 @@ inline IteratorRange<Module::inst_iterator> Module::execution_modes() {
}
inline IteratorRange<Module::const_inst_iterator> Module::execution_modes()
const {
const {
return make_range(execution_modes_.begin(), execution_modes_.end());
}

View File

@ -25,7 +25,9 @@ namespace opt {
class NullPass : public Pass {
public:
const char* name() const override { return "null"; }
Status Process(ir::IRContext*) override { return Status::SuccessWithoutChange; }
Status Process(ir::IRContext*) override {
return Status::SuccessWithoutChange;
}
};
} // namespace opt

View File

@ -87,7 +87,7 @@ class Pass {
// Returns a pointer to the CFG for current module. TODO(dnovillo): This
// should belong in IRContext.
ir::CFG *cfg() const { return cfg_.get(); }
ir::CFG* cfg() const { return cfg_.get(); }
// Add to |todo| all ids of functions called in |func|.
void AddCalls(ir::Function* func, std::queue<uint32_t>* todo);
@ -111,8 +111,8 @@ class Pass {
const std::unordered_map<uint32_t, ir::Function*>& id2function,
std::queue<uint32_t>* roots);
// Run the pass on the given |module|. Returns Status::Failure if errors occur when
// Run the pass on the given |module|. Returns Status::Failure if errors occur
// when
// processing. Returns the corresponding Status::Success if processing is
// successful to indicate whether changes are made to the module. If there
// were any changes it will also invalidate the analyses in the IRContext

View File

@ -22,8 +22,8 @@
#include "module.h"
#include "pass.h"
#include "spirv-tools/libspirv.hpp"
#include "ir_context.h"
#include "spirv-tools/libspirv.hpp"
namespace spvtools {
namespace opt {

View File

@ -17,6 +17,7 @@
// A single header to include all passes.
#include "aggressive_dead_code_elim_pass.h"
#include "block_merge_pass.h"
#include "cfg_cleanup_pass.h"
#include "common_uniform_elim_pass.h"
@ -24,22 +25,21 @@
#include "dead_branch_elim_pass.h"
#include "dead_variable_elimination.h"
#include "eliminate_dead_constant_pass.h"
#include "eliminate_dead_functions_pass.h"
#include "flatten_decoration_pass.h"
#include "fold_spec_constant_op_and_composite_pass.h"
#include "freeze_spec_constant_value_pass.h"
#include "inline_exhaustive_pass.h"
#include "inline_opaque_pass.h"
#include "insert_extract_elim.h"
#include "local_access_chain_convert_pass.h"
#include "local_single_block_elim_pass.h"
#include "local_single_store_elim_pass.h"
#include "local_ssa_elim_pass.h"
#include "freeze_spec_constant_value_pass.h"
#include "local_access_chain_convert_pass.h"
#include "aggressive_dead_code_elim_pass.h"
#include "null_pass.h"
#include "set_spec_constant_default_value_pass.h"
#include "strength_reduction_pass.h"
#include "strip_debug_info_pass.h"
#include "unify_const_pass.h"
#include "eliminate_dead_functions_pass.h"
#endif // LIBSPIRV_OPT_PASSES_H_

View File

@ -23,8 +23,8 @@
#include <vector>
#include "decoration_manager.h"
#include "opcode.h"
#include "ir_context.h"
#include "opcode.h"
namespace spvtools {
namespace opt {
@ -46,11 +46,13 @@ Pass::Status RemoveDuplicatesPass::Process(ir::IRContext* irContext) {
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
bool RemoveDuplicatesPass::RemoveDuplicateCapabilities(ir::IRContext* irContext) const {
bool RemoveDuplicatesPass::RemoveDuplicateCapabilities(
ir::IRContext* irContext) const {
bool modified = false;
std::unordered_set<uint32_t> capabilities;
for (auto i = irContext->capability_begin(); i != irContext->capability_end();) {
for (auto i = irContext->capability_begin();
i != irContext->capability_end();) {
auto res = capabilities.insert(i->GetSingleWordOperand(0u));
if (res.second) {
@ -66,8 +68,8 @@ bool RemoveDuplicatesPass::RemoveDuplicateCapabilities(ir::IRContext* irContext)
return modified;
}
bool
RemoveDuplicatesPass::RemoveDuplicatesExtInstImports(ir::IRContext* irContext) const {
bool RemoveDuplicatesPass::RemoveDuplicatesExtInstImports(
ir::IRContext* irContext) const {
bool modified = false;
std::unordered_map<std::string, SpvId> extInstImports;
@ -90,8 +92,8 @@ RemoveDuplicatesPass::RemoveDuplicatesExtInstImports(ir::IRContext* irContext) c
return modified;
}
bool RemoveDuplicatesPass::RemoveDuplicateTypes(ir::IRContext* irContext,
DecorationManager& decManager) const {
bool RemoveDuplicatesPass::RemoveDuplicateTypes(
ir::IRContext* irContext, DecorationManager& decManager) const {
bool modified = false;
std::vector<Instruction> visitedTypes;
@ -142,7 +144,8 @@ bool RemoveDuplicatesPass::RemoveDuplicateDecorations(
std::vector<const Instruction*> visitedDecorations;
opt::analysis::DecorationManager decorationManager(irContext->module());
for (auto i = irContext->annotation_begin(); i != irContext->annotation_end();) {
for (auto i = irContext->annotation_begin();
i != irContext->annotation_end();) {
// Is the current decoration equal to one of the decorations we have aready
// visited?
bool alreadyVisited = false;

View File

@ -19,9 +19,9 @@
#include "decoration_manager.h"
#include "def_use_manager.h"
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {
@ -44,7 +44,7 @@ class RemoveDuplicatesPass : public Pass {
bool RemoveDuplicateCapabilities(ir::IRContext* irContext) const;
bool RemoveDuplicatesExtInstImports(ir::IRContext* irContext) const;
bool RemoveDuplicateTypes(ir::IRContext* irContext,
analysis::DecorationManager& decManager) const;
analysis::DecorationManager& decManager) const;
bool RemoveDuplicateDecorations(ir::IRContext* irContext) const;
};

View File

@ -21,12 +21,12 @@
#include <vector>
#include "def_use_manager.h"
#include "ir_context.h"
#include "make_unique.h"
#include "spirv-tools/libspirv.h"
#include "type_manager.h"
#include "types.h"
#include "util/parse_number.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {
@ -188,7 +188,8 @@ ir::Instruction* GetSpecIdTargetFromDecorationGroup(
}
};
Pass::Status SetSpecConstantDefaultValuePass::Process(ir::IRContext* irContext) {
Pass::Status SetSpecConstantDefaultValuePass::Process(
ir::IRContext* irContext) {
// The operand index of decoration target in an OpDecorate instruction.
const uint32_t kTargetIdOperandIndex = 0;
// The operand index of the decoration literal in an OpDecorate instruction.
@ -254,8 +255,8 @@ Pass::Status SetSpecConstantDefaultValuePass::Process(ir::IRContext* irContext)
// Gets the string of the default value and parses it to bit pattern
// with the type of the spec constant.
const std::string& default_value_str = iter->second;
bit_pattern = ParseDefaultValueStr(default_value_str.c_str(),
type_mgr.GetType(spec_inst->type_id()));
bit_pattern = ParseDefaultValueStr(
default_value_str.c_str(), type_mgr.GetType(spec_inst->type_id()));
} else {
// Search for the new bit-pattern-form default value for this spec id.

View File

@ -19,9 +19,9 @@
#include <string>
#include <unordered_map>
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {
@ -38,17 +38,22 @@ class SetSpecConstantDefaultValuePass : public Pass {
// in the form of string.
explicit SetSpecConstantDefaultValuePass(
const SpecIdToValueStrMap& default_values)
: spec_id_to_value_str_(default_values), spec_id_to_value_bit_pattern_() {}
: spec_id_to_value_str_(default_values),
spec_id_to_value_bit_pattern_() {}
explicit SetSpecConstantDefaultValuePass(SpecIdToValueStrMap&& default_values)
: spec_id_to_value_str_(std::move(default_values)), spec_id_to_value_bit_pattern_() {}
: spec_id_to_value_str_(std::move(default_values)),
spec_id_to_value_bit_pattern_() {}
// Constructs a pass instance with a map from spec ids to default values in
// the form of bit pattern.
explicit SetSpecConstantDefaultValuePass(
const SpecIdToValueBitPatternMap& default_values)
: spec_id_to_value_str_(), spec_id_to_value_bit_pattern_(default_values) {}
explicit SetSpecConstantDefaultValuePass(SpecIdToValueBitPatternMap&& default_values)
: spec_id_to_value_str_(), spec_id_to_value_bit_pattern_(std::move(default_values)) {}
: spec_id_to_value_str_(),
spec_id_to_value_bit_pattern_(default_values) {}
explicit SetSpecConstantDefaultValuePass(
SpecIdToValueBitPatternMap&& default_values)
: spec_id_to_value_str_(),
spec_id_to_value_bit_pattern_(std::move(default_values)) {}
const char* name() const override { return "set-spec-const-default-value"; }
Status Process(ir::IRContext*) override;
@ -96,7 +101,8 @@ class SetSpecConstantDefaultValuePass : public Pass {
// The mapping from spec ids to their string-form default values to be set.
const SpecIdToValueStrMap spec_id_to_value_str_;
// The mapping from spec ids to their bitpattern-form default values to be set.
// The mapping from spec ids to their bitpattern-form default values to be
// set.
const SpecIdToValueBitPatternMap spec_id_to_value_bit_pattern_;
};

View File

@ -21,9 +21,9 @@
#include <unordered_set>
#include "def_use_manager.h"
#include "ir_context.h"
#include "log.h"
#include "reflect.h"
#include "ir_context.h"
namespace {
// Count the number of trailing zeros in the binary representation of

View File

@ -16,9 +16,9 @@
#define LIBSPIRV_OPT_STRENGTH_REDUCTION_PASS_H_
#include "def_use_manager.h"
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {
@ -34,8 +34,10 @@ class StrengthReductionPass : public Pass {
// Returns true if something changed.
bool ReplaceMultiplyByPowerOf2(ir::BasicBlock::iterator*);
// Scan the types and constants in the module looking for the the integer types that we are
// interested in. The shift operation needs a small unsigned integer. We need to find
// Scan the types and constants in the module looking for the the integer
// types that we are
// interested in. The shift operation needs a small unsigned integer. We
// need to find
// them or create them. We do not want duplicates.
void FindIntTypesAndConstants();

View File

@ -19,7 +19,8 @@ namespace spvtools {
namespace opt {
Pass::Status StripDebugInfoPass::Process(ir::IRContext* irContext) {
bool modified = !irContext->debugs1().empty() || !irContext->debugs2().empty() ||
bool modified = !irContext->debugs1().empty() ||
!irContext->debugs2().empty() ||
!irContext->debugs3().empty();
irContext->debug_clear();

View File

@ -15,9 +15,9 @@
#ifndef LIBSPIRV_OPT_STRIP_DEBUG_INFO_PASS_H_
#define LIBSPIRV_OPT_STRIP_DEBUG_INFO_PASS_H_
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {

View File

@ -42,10 +42,10 @@ bool CompareTwoVectors(const U32VecVec a, const U32VecVec b) {
b_ptrs.push_back(&b[i]);
}
const auto cmp =
[](const std::vector<uint32_t>* m, const std::vector<uint32_t>* n) {
return m->front() < n->front();
};
const auto cmp = [](const std::vector<uint32_t>* m,
const std::vector<uint32_t>* n) {
return m->front() < n->front();
};
std::sort(a_ptrs.begin(), a_ptrs.end(), cmp);
std::sort(b_ptrs.begin(), b_ptrs.end(), cmp);

View File

@ -18,8 +18,8 @@
#include <utility>
#include "def_use_manager.h"
#include "make_unique.h"
#include "ir_context.h"
#include "make_unique.h"
namespace spvtools {
namespace opt {

View File

@ -15,9 +15,9 @@
#ifndef LIBSPIRV_OPT_UNIFY_CONSTANT_PASS_H_
#define LIBSPIRV_OPT_UNIFY_CONSTANT_PASS_H_
#include "ir_context.h"
#include "module.h"
#include "pass.h"
#include "ir_context.h"
namespace spvtools {
namespace opt {

View File

@ -14,7 +14,8 @@
#include "print.h"
#if defined(SPIRV_ANDROID) || defined(SPIRV_LINUX) || defined(SPIRV_MAC) || defined(SPIRV_FREEBSD)
#if defined(SPIRV_ANDROID) || defined(SPIRV_LINUX) || defined(SPIRV_MAC) || \
defined(SPIRV_FREEBSD)
namespace libspirv {
clr::reset::operator const char*() { return "\x1b[0m"; }
@ -35,8 +36,7 @@ clr::blue::operator const char*() { return "\x1b[34m"; }
namespace libspirv {
static void SetConsoleForegroundColorPrimary(HANDLE hConsole, WORD color)
{
static void SetConsoleForegroundColorPrimary(HANDLE hConsole, WORD color) {
// Get screen buffer information from console handle
CONSOLE_SCREEN_BUFFER_INFO bufInfo;
GetConsoleScreenBufferInfo(hConsole, &bufInfo);
@ -48,8 +48,7 @@ static void SetConsoleForegroundColorPrimary(HANDLE hConsole, WORD color)
SetConsoleTextAttribute(hConsole, color);
}
static void SetConsoleForegroundColor(WORD color)
{
static void SetConsoleForegroundColor(WORD color) {
SetConsoleForegroundColorPrimary(GetStdHandle(STD_OUTPUT_HANDLE), color);
SetConsoleForegroundColorPrimary(GetStdHandle(STD_ERROR_HANDLE), color);
}

View File

@ -22,10 +22,6 @@ const char* kBuildVersions[] = {
} // anonymous namespace
const char* spvSoftwareVersionString() {
return kBuildVersions[0];
}
const char* spvSoftwareVersionString() { return kBuildVersions[0]; }
const char* spvSoftwareVersionDetailsString() {
return kBuildVersions[1];
}
const char* spvSoftwareVersionDetailsString() { return kBuildVersions[1]; }

View File

@ -25,16 +25,16 @@
#include "diagnostic.h"
#include "enum_string_mapping.h"
#include "extensions.h"
#include "instruction.h"
#include "id_descriptor.h"
#include "instruction.h"
#include "opcode.h"
#include "operand.h"
#include "spirv-tools/libspirv.h"
#include "spirv_endian.h"
#include "spirv_validator_options.h"
#include "validate.h"
#include "val/instruction.h"
#include "val/validation_state.h"
#include "validate.h"
using libspirv::IdDescriptorCollection;
using libspirv::Instruction;
@ -54,10 +54,10 @@ class StatsAggregator {
}
// Collects header statistics and sets correct id_bound.
spv_result_t ProcessHeader(
spv_endianness_t /* endian */, uint32_t /* magic */,
uint32_t version, uint32_t generator, uint32_t id_bound,
uint32_t /* schema */) {
spv_result_t ProcessHeader(spv_endianness_t /* endian */,
uint32_t /* magic */, uint32_t version,
uint32_t generator, uint32_t id_bound,
uint32_t /* schema */) {
vstate_->setIdBound(id_bound);
++stats_->version_hist[version];
++stats_->generator_hist[generator];
@ -68,9 +68,9 @@ class StatsAggregator {
// then procession the instruction to collect stats.
spv_result_t ProcessInstruction(const spv_parsed_instruction_t* inst) {
const spv_result_t validation_result =
spvtools::ValidateInstructionAndUpdateValidationState(vstate_.get(), inst);
if (validation_result != SPV_SUCCESS)
return validation_result;
spvtools::ValidateInstructionAndUpdateValidationState(vstate_.get(),
inst);
if (validation_result != SPV_SUCCESS) return validation_result;
ProcessOpcode();
ProcessCapability();
@ -106,8 +106,9 @@ class StatsAggregator {
id_descriptors_.GetDescriptor(inst.word(operand.offset));
if (descriptor) {
++stats_->id_descriptor_hist[descriptor];
++stats_->operand_slot_id_descriptor_hist[
std::pair<uint32_t, uint32_t>(inst.opcode(), index)][descriptor];
++stats_
->operand_slot_id_descriptor_hist[std::pair<uint32_t, uint32_t>(
inst.opcode(), index)][descriptor];
}
}
++index;
@ -168,8 +169,8 @@ class StatsAggregator {
uint32_t index = 0;
for (const auto& operand : inst.operands()) {
if (operand.num_words == 1 && !spvIsIdType(operand.type)) {
++stats_->operand_slot_non_id_words_hist[std::pair<uint32_t, uint32_t>(
inst.opcode(), index)][inst.word(operand.offset)];
++stats_->operand_slot_non_id_words_hist[std::pair<uint32_t, uint32_t>(
inst.opcode(), index)][inst.word(operand.offset)];
}
++index;
}
@ -205,13 +206,14 @@ class StatsAggregator {
if (inst_it != vstate_->ordered_instructions().rend()) {
const SpvOp prev_opcode = inst_it->opcode();
++stats_->opcode_and_num_operands_markov_hist[prev_opcode][
opcode_and_num_operands];
++stats_->opcode_and_num_operands_markov_hist[prev_opcode]
[opcode_and_num_operands];
}
auto step_it = stats_->opcode_markov_hist.begin();
for (; inst_it != vstate_->ordered_instructions().rend() &&
step_it != stats_->opcode_markov_hist.end(); ++inst_it, ++step_it) {
step_it != stats_->opcode_markov_hist.end();
++inst_it, ++step_it) {
auto& hist = (*step_it)[inst_it->opcode()];
++hist[opcode];
}
@ -260,9 +262,7 @@ class StatsAggregator {
}
}
SpirvStats* stats() {
return stats_;
}
SpirvStats* stats() { return stats_; }
private:
// Returns the current instruction (the one last processed by the validator).
@ -276,18 +276,17 @@ class StatsAggregator {
IdDescriptorCollection id_descriptors_;
};
spv_result_t ProcessHeader(
void* user_data, spv_endianness_t endian, uint32_t magic,
uint32_t version, uint32_t generator, uint32_t id_bound,
uint32_t schema) {
spv_result_t ProcessHeader(void* user_data, spv_endianness_t endian,
uint32_t magic, uint32_t version, uint32_t generator,
uint32_t id_bound, uint32_t schema) {
StatsAggregator* stats_aggregator =
reinterpret_cast<StatsAggregator*>(user_data);
return stats_aggregator->ProcessHeader(
endian, magic, version, generator, id_bound, schema);
return stats_aggregator->ProcessHeader(endian, magic, version, generator,
id_bound, schema);
}
spv_result_t ProcessInstruction(
void* user_data, const spv_parsed_instruction_t* inst) {
spv_result_t ProcessInstruction(void* user_data,
const spv_parsed_instruction_t* inst) {
StatsAggregator* stats_aggregator =
reinterpret_cast<StatsAggregator*>(user_data);
return stats_aggregator->ProcessInstruction(inst);
@ -297,9 +296,9 @@ spv_result_t ProcessInstruction(
namespace libspirv {
spv_result_t AggregateStats(
const spv_context_t& context, const uint32_t* words, const size_t num_words,
spv_diagnostic* pDiagnostic, SpirvStats* stats) {
spv_result_t AggregateStats(const spv_context_t& context, const uint32_t* words,
const size_t num_words, spv_diagnostic* pDiagnostic,
SpirvStats* stats) {
spv_const_binary_t binary = {words, num_words};
spv_endianness_t endian;
@ -307,14 +306,14 @@ spv_result_t AggregateStats(
if (spvBinaryEndianness(&binary, &endian)) {
return libspirv::DiagnosticStream(position, context.consumer,
SPV_ERROR_INVALID_BINARY)
<< "Invalid SPIR-V magic number.";
<< "Invalid SPIR-V magic number.";
}
spv_header_t header;
if (spvBinaryHeaderGet(&binary, endian, &header)) {
return libspirv::DiagnosticStream(position, context.consumer,
SPV_ERROR_INVALID_BINARY)
<< "Invalid SPIR-V header.";
<< "Invalid SPIR-V header.";
}
StatsAggregator stats_aggregator(stats, &context);

View File

@ -69,15 +69,15 @@ struct SpirvStats {
std::unordered_map<double, uint32_t> f64_constant_hist;
// Enum histogram, operand type -> operand value -> count.
std::unordered_map<uint32_t,
std::unordered_map<uint32_t, uint32_t>> enum_hist;
std::unordered_map<uint32_t, std::unordered_map<uint32_t, uint32_t>>
enum_hist;
// Histogram of all non-id single words.
// pair<opcode, operand index> -> value -> count.
// This is a generalization of enum_hist, also includes literal integers and
// masks.
std::map<std::pair<uint32_t, uint32_t>,
std::map<uint32_t, uint32_t>> operand_slot_non_id_words_hist;
std::map<std::pair<uint32_t, uint32_t>, std::map<uint32_t, uint32_t>>
operand_slot_non_id_words_hist;
// Historgam of descriptors generated by IdDescriptorCollection.
// Descriptor -> count.
@ -88,10 +88,11 @@ struct SpirvStats {
// Historgam of descriptors generated by IdDescriptorCollection for every
// operand slot. pair<opcode, operand index> -> descriptor -> count.
std::map<std::pair<uint32_t, uint32_t>,
std::map<uint32_t, uint32_t>> operand_slot_id_descriptor_hist;
std::map<std::pair<uint32_t, uint32_t>, std::map<uint32_t, uint32_t>>
operand_slot_id_descriptor_hist;
// Histogram of literal strings, sharded by opcodes, opcode -> string -> count.
// Histogram of literal strings, sharded by opcodes, opcode -> string ->
// count.
// This is suboptimal if an opcode has multiple literal string operands,
// as it wouldn't differentiate between operands.
std::unordered_map<uint32_t, std::unordered_map<std::string, uint32_t>>
@ -114,14 +115,15 @@ struct SpirvStats {
// The size of the outer std::vector also serves as an input parameter,
// determining how many steps will be collected.
// I.e. do opcode_markov_hist.resize(1) to collect data for one step only.
std::vector<std::unordered_map<uint32_t,
std::unordered_map<uint32_t, uint32_t>>> opcode_markov_hist;
std::vector<
std::unordered_map<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
opcode_markov_hist;
};
// Aggregates existing |stats| with new stats extracted from |binary|.
spv_result_t AggregateStats(
const spv_context_t& context, const uint32_t* words, const size_t num_words,
spv_diagnostic* pDiagnostic, SpirvStats* stats);
spv_result_t AggregateStats(const spv_context_t& context, const uint32_t* words,
const size_t num_words, spv_diagnostic* pDiagnostic,
SpirvStats* stats);
} // namespace libspirv

View File

@ -37,12 +37,10 @@ struct validator_universal_limits_t {
// Manages command line options passed to the SPIR-V Validator. New struct
// members may be added for any new option.
struct spv_validator_options_t {
spv_validator_options_t()
: universal_limits_(), relax_struct_store(false) {}
spv_validator_options_t() : universal_limits_(), relax_struct_store(false) {}
validator_universal_limits_t universal_limits_;
bool relax_struct_store;
};
#endif // LIBSPIRV_SPIRV_VALIDATOR_OPTIONS_H_

View File

@ -241,8 +241,8 @@ spv_result_t spvTextEncodeOperand(const libspirv::AssemblyGrammar& grammar,
// and emits its corresponding number.
spv_ext_inst_desc extInst;
if (grammar.lookupExtInst(pInst->extInstType, textValue, &extInst)) {
return context->diagnostic() << "Invalid extended instruction name '"
<< textValue << "'.";
return context->diagnostic()
<< "Invalid extended instruction name '" << textValue << "'.";
}
spvInstructionAddWord(pInst, extInst->ext_inst);
@ -522,8 +522,8 @@ spv_result_t spvTextEncodeOpcode(const libspirv::AssemblyGrammar& grammar,
error = context->getWord(&opcodeName, &nextPosition);
if (error) return context->diagnostic(error) << "Internal Error";
if (!context->startsWithOp()) {
return context->diagnostic() << "Invalid Opcode prefix '" << opcodeName
<< "'.";
return context->diagnostic()
<< "Invalid Opcode prefix '" << opcodeName << "'.";
}
}
@ -533,8 +533,8 @@ spv_result_t spvTextEncodeOpcode(const libspirv::AssemblyGrammar& grammar,
spv_opcode_desc opcodeEntry;
error = grammar.lookupOpcode(pInstName, &opcodeEntry);
if (error) {
return context->diagnostic(error) << "Invalid Opcode name '" << opcodeName
<< "'";
return context->diagnostic(error)
<< "Invalid Opcode name '" << opcodeName << "'";
}
if (opcodeEntry->hasResult && result_id.empty()) {
return context->diagnostic()
@ -556,7 +556,8 @@ spv_result_t spvTextEncodeOpcode(const libspirv::AssemblyGrammar& grammar,
spv_operand_pattern_t expectedOperands;
expectedOperands.reserve(opcodeEntry->numTypes);
for (auto i = 0; i < opcodeEntry->numTypes; i++)
expectedOperands.push_back(opcodeEntry->operandTypes[opcodeEntry->numTypes - i - 1]);
expectedOperands.push_back(
opcodeEntry->operandTypes[opcodeEntry->numTypes - i - 1]);
while (!expectedOperands.empty()) {
const spv_operand_type_t type = expectedOperands.back();
@ -694,10 +695,11 @@ spv_result_t GetNumericIds(const libspirv::AssemblyGrammar& grammar,
// Translates a given assembly language module into binary form.
// If a diagnostic is generated, it is not yet marked as being
// for a text-based input.
spv_result_t spvTextToBinaryInternal(
const libspirv::AssemblyGrammar& grammar,
const spvtools::MessageConsumer& consumer, const spv_text text,
const uint32_t options, spv_binary* pBinary) {
spv_result_t spvTextToBinaryInternal(const libspirv::AssemblyGrammar& grammar,
const spvtools::MessageConsumer& consumer,
const spv_text text,
const uint32_t options,
spv_binary* pBinary) {
// The ids in this set will have the same values both in source and binary.
// All other ids will be generated by filling in the gaps.
std::set<uint32_t> ids_to_preserve;
@ -770,15 +772,17 @@ spv_result_t spvTextToBinary(const spv_const_context context,
const char* input_text,
const size_t input_text_size, spv_binary* pBinary,
spv_diagnostic* pDiagnostic) {
return spvTextToBinaryWithOptions(
context, input_text, input_text_size, SPV_BINARY_TO_TEXT_OPTION_NONE,
pBinary, pDiagnostic);
return spvTextToBinaryWithOptions(context, input_text, input_text_size,
SPV_BINARY_TO_TEXT_OPTION_NONE, pBinary,
pDiagnostic);
}
spv_result_t spvTextToBinaryWithOptions(
const spv_const_context context, const char* input_text,
const size_t input_text_size, const uint32_t options, spv_binary* pBinary,
spv_diagnostic* pDiagnostic) {
spv_result_t spvTextToBinaryWithOptions(const spv_const_context context,
const char* input_text,
const size_t input_text_size,
const uint32_t options,
spv_binary* pBinary,
spv_diagnostic* pDiagnostic) {
spv_context_t hijack_context = *context;
if (pDiagnostic) {
*pDiagnostic = nullptr;

View File

@ -389,8 +389,7 @@ std::set<uint32_t> AssemblyContext::GetNumericIds() const {
std::set<uint32_t> ids;
for (const auto& kv : named_ids_) {
uint32_t id;
if (spvutils::ParseNumber(kv.first.c_str(), &id))
ids.insert(id);
if (spvutils::ParseNumber(kv.first.c_str(), &id)) ids.insert(id);
}
return ids;
}

View File

@ -119,8 +119,12 @@ class AssemblyContext {
public:
AssemblyContext(spv_text text, const spvtools::MessageConsumer& consumer,
std::set<uint32_t>&& ids_to_preserve = std::set<uint32_t>())
: current_position_({}), consumer_(consumer), text_(text), bound_(1),
next_id_(1), ids_to_preserve_(std::move(ids_to_preserve)) {}
: current_position_({}),
consumer_(consumer),
text_(text),
bound_(1),
next_id_(1),
ids_to_preserve_(std::move(ids_to_preserve)) {}
// Assigns a new integer value to the given text ID, or returns the previously
// assigned integer value if the ID has been seen before.

View File

@ -121,15 +121,13 @@ bool ReadVariableWidthInternal(BitReaderInterface* reader, uint64_t* val,
while (payload_read + chunk_length < max_payload) {
uint64_t bits = 0;
if (reader->ReadBits(&bits, chunk_length) != chunk_length)
return false;
if (reader->ReadBits(&bits, chunk_length) != chunk_length) return false;
*val |= bits << payload_read;
payload_read += chunk_length;
uint64_t more_to_come = 0;
if (reader->ReadBits(&more_to_come, 1) != 1)
return false;
if (reader->ReadBits(&more_to_come, 1) != 1) return false;
if (!more_to_come) {
return true;
@ -139,8 +137,7 @@ bool ReadVariableWidthInternal(BitReaderInterface* reader, uint64_t* val,
// Need to read the last chunk which may be truncated. No signal bit follows.
uint64_t bits = 0;
const size_t left_to_read = max_payload - payload_read;
if (reader->ReadBits(&bits, left_to_read) != left_to_read)
return false;
if (reader->ReadBits(&bits, left_to_read) != left_to_read) return false;
*val |= bits << payload_read;
return true;
@ -255,26 +252,22 @@ void BitWriterInterface::WriteVariableWidthU8(uint8_t val,
WriteVariableWidthUnsigned(this, val, chunk_length);
}
void BitWriterInterface::WriteVariableWidthS64(int64_t val,
size_t chunk_length,
void BitWriterInterface::WriteVariableWidthS64(int64_t val, size_t chunk_length,
size_t zigzag_exponent) {
WriteVariableWidthSigned(this, val, chunk_length, zigzag_exponent);
}
void BitWriterInterface::WriteVariableWidthS32(int32_t val,
size_t chunk_length,
void BitWriterInterface::WriteVariableWidthS32(int32_t val, size_t chunk_length,
size_t zigzag_exponent) {
WriteVariableWidthSigned(this, val, chunk_length, zigzag_exponent);
}
void BitWriterInterface::WriteVariableWidthS16(int16_t val,
size_t chunk_length,
void BitWriterInterface::WriteVariableWidthS16(int16_t val, size_t chunk_length,
size_t zigzag_exponent) {
WriteVariableWidthSigned(this, val, chunk_length, zigzag_exponent);
}
void BitWriterInterface::WriteVariableWidthS8(int8_t val,
size_t chunk_length,
void BitWriterInterface::WriteVariableWidthS8(int8_t val, size_t chunk_length,
size_t zigzag_exponent) {
WriteVariableWidthSigned(this, val, chunk_length, zigzag_exponent);
}
@ -352,26 +345,22 @@ bool BitReaderInterface::ReadVariableWidthU8(uint8_t* val,
return ReadVariableWidthUnsigned(this, val, chunk_length);
}
bool BitReaderInterface::ReadVariableWidthS64(int64_t* val,
size_t chunk_length,
bool BitReaderInterface::ReadVariableWidthS64(int64_t* val, size_t chunk_length,
size_t zigzag_exponent) {
return ReadVariableWidthSigned(this, val, chunk_length, zigzag_exponent);
}
bool BitReaderInterface::ReadVariableWidthS32(int32_t* val,
size_t chunk_length,
bool BitReaderInterface::ReadVariableWidthS32(int32_t* val, size_t chunk_length,
size_t zigzag_exponent) {
return ReadVariableWidthSigned(this, val, chunk_length, zigzag_exponent);
}
bool BitReaderInterface::ReadVariableWidthS16(int16_t* val,
size_t chunk_length,
bool BitReaderInterface::ReadVariableWidthS16(int16_t* val, size_t chunk_length,
size_t zigzag_exponent) {
return ReadVariableWidthSigned(this, val, chunk_length, zigzag_exponent);
}
bool BitReaderInterface::ReadVariableWidthS8(int8_t* val,
size_t chunk_length,
bool BitReaderInterface::ReadVariableWidthS8(int8_t* val, size_t chunk_length,
size_t zigzag_exponent) {
return ReadVariableWidthSigned(this, val, chunk_length, zigzag_exponent);
}
@ -396,8 +385,7 @@ size_t BitReaderWord64::ReadBits(uint64_t* bits, size_t num_bits) {
assert(is_little_endian && "Big-endian architecture support not implemented");
if (!is_little_endian) return 0;
if (ReachedEnd())
return 0;
if (ReachedEnd()) return 0;
// Index of the current word.
const size_t index = pos_ / 64;
@ -431,17 +419,13 @@ size_t BitReaderWord64::ReadBits(uint64_t* bits, size_t num_bits) {
return num_bits;
}
bool BitReaderWord64::ReachedEnd() const {
return pos_ >= buffer_.size() * 64;
}
bool BitReaderWord64::ReachedEnd() const { return pos_ >= buffer_.size() * 64; }
bool BitReaderWord64::OnlyZeroesLeft() const {
if (ReachedEnd())
return true;
if (ReachedEnd()) return true;
const size_t index = pos_ / 64;
if (index < buffer_.size() - 1)
return false;
if (index < buffer_.size() - 1) return false;
assert(index == buffer_.size() - 1);

View File

@ -21,8 +21,8 @@
#include <bitset>
#include <cstdint>
#include <functional>
#include <string>
#include <sstream>
#include <string>
#include <vector>
namespace spvutils {
@ -60,9 +60,7 @@ inline T GetLowerBits(T in, size_t num_bits) {
// 2 -> 4
// Motivation: -1 is 0xFF...FF what doesn't work very well with
// WriteVariableWidth which prefers to have as many 0 bits as possible.
inline uint64_t EncodeZigZag(int64_t val) {
return (val << 1) ^ (val >> 63);
}
inline uint64_t EncodeZigZag(int64_t val) { return (val << 1) ^ (val >> 63); }
// Decodes signed integer encoded with EncodeZigZag.
inline int64_t DecodeZigZag(uint64_t val) {
@ -92,7 +90,8 @@ inline int64_t DecodeZigZag(uint64_t val) {
inline uint64_t EncodeZigZag(int64_t val, size_t block_exponent) {
assert(block_exponent < 64);
const uint64_t uval = static_cast<uint64_t>(val >= 0 ? val : -val - 1);
const uint64_t block_num = ((uval >> block_exponent) << 1) + (val >= 0 ? 0 : 1);
const uint64_t block_num =
((uval >> block_exponent) << 1) + (val >= 0 ? 0 : 1);
const uint64_t pos = GetLowerBits(uval, block_exponent);
return (block_num << block_exponent) + pos;
}
@ -139,13 +138,13 @@ std::vector<T> StreamToBuffer(std::string str) {
std::vector<T> buffer;
buffer.reserve(NumBitsToNumWords<sizeof(T)>(str.length()));
for (int index = str_length - word_size; index >= 0; index -= word_size) {
buffer.push_back(static_cast<T>(std::bitset<sizeof(T) * 8>(
str, index, word_size).to_ullong()));
buffer.push_back(static_cast<T>(
std::bitset<sizeof(T) * 8>(str, index, word_size).to_ullong()));
}
const size_t suffix_length = str.length() % word_size;
if (suffix_length != 0) {
buffer.push_back(static_cast<T>(std::bitset<sizeof(T) * 8>(
str, 0, suffix_length).to_ullong()));
buffer.push_back(static_cast<T>(
std::bitset<sizeof(T) * 8>(str, 0, suffix_length).to_ullong()));
}
return buffer;
}
@ -154,8 +153,7 @@ std::vector<T> StreamToBuffer(std::string str) {
template <size_t N>
inline std::string PadToWord(std::string&& str) {
const size_t tail_length = str.size() % N;
if (tail_length != 0)
str += std::string(N - tail_length, '0');
if (tail_length != 0) str += std::string(N - tail_length, '0');
return str;
}
@ -174,7 +172,8 @@ inline std::bitset<N> StreamToBitset(std::string str) {
// Converts first |num_bits| of std::bitset to a left-to-right stream of bits.
template <size_t N>
inline std::string BitsetToStream(const std::bitset<N>& bits, size_t num_bits = N) {
inline std::string BitsetToStream(const std::bitset<N>& bits,
size_t num_bits = N) {
std::string str = bits.to_string().substr(N - num_bits);
std::reverse(str.begin(), str.end());
return str;
@ -237,14 +236,14 @@ class BitWriterInterface {
void WriteVariableWidthU32(uint32_t val, size_t chunk_length);
void WriteVariableWidthU16(uint16_t val, size_t chunk_length);
void WriteVariableWidthU8(uint8_t val, size_t chunk_length);
void WriteVariableWidthS64(
int64_t val, size_t chunk_length, size_t zigzag_exponent);
void WriteVariableWidthS32(
int32_t val, size_t chunk_length, size_t zigzag_exponent);
void WriteVariableWidthS16(
int16_t val, size_t chunk_length, size_t zigzag_exponent);
void WriteVariableWidthS8(
int8_t val, size_t chunk_length, size_t zigzag_exponent);
void WriteVariableWidthS64(int64_t val, size_t chunk_length,
size_t zigzag_exponent);
void WriteVariableWidthS32(int32_t val, size_t chunk_length,
size_t zigzag_exponent);
void WriteVariableWidthS16(int16_t val, size_t chunk_length,
size_t zigzag_exponent);
void WriteVariableWidthS8(int8_t val, size_t chunk_length,
size_t zigzag_exponent);
// Writes |val| using fixed bit width. Bit width is determined by |max_val|:
// max_val 0 -> bit width 1
@ -262,14 +261,10 @@ class BitWriterInterface {
virtual size_t GetNumBits() const = 0;
// Provides direct access to the buffer data if implemented.
virtual const uint8_t* GetData() const {
return nullptr;
}
virtual const uint8_t* GetData() const { return nullptr; }
// Returns buffer size in bytes.
size_t GetDataSizeBytes() const {
return NumBitsToNumWords<8>(GetNumBits());
}
size_t GetDataSizeBytes() const { return NumBitsToNumWords<8>(GetNumBits()); }
// Generates and returns byte array containing written bits.
virtual std::vector<uint8_t> GetDataCopy() const = 0;
@ -286,9 +281,7 @@ class BitWriterWord64 : public BitWriterInterface {
void WriteBits(uint64_t bits, size_t num_bits) override;
size_t GetNumBits() const override {
return end_;
}
size_t GetNumBits() const override { return end_; }
const uint8_t* GetData() const override {
return reinterpret_cast<const uint8_t*>(buffer_.data());
@ -300,9 +293,7 @@ class BitWriterWord64 : public BitWriterInterface {
// Returns written stream as std::string, padded with zeroes so that the
// length is a multiple of 64.
std::string GetStreamPadded64() const {
return BufferToStream(buffer_);
}
std::string GetStreamPadded64() const { return BufferToStream(buffer_); }
// Sets callback to emit bit sequences after every write.
void SetCallback(std::function<void(const std::string&)> callback) {
@ -312,8 +303,7 @@ class BitWriterWord64 : public BitWriterInterface {
protected:
// Sends string generated from arguments to callback_ if defined.
void EmitSequence(uint64_t bits, size_t num_bits) const {
if (callback_)
callback_(BitsToStream(bits, num_bits));
if (callback_) callback_(BitsToStream(bits, num_bits));
}
private:
@ -363,8 +353,7 @@ class BitReaderInterface {
static_assert(sizeof(T) <= 64, "Type size too large");
uint64_t bits = 0;
const size_t num_read = ReadBits(&bits, sizeof(T) * 8);
if (num_read != sizeof(T) * 8)
return false;
if (num_read != sizeof(T) * 8) return false;
memcpy(val, &bits, sizeof(T));
return true;
}
@ -384,9 +373,7 @@ class BitReaderInterface {
// the buffer stream ends with padding zeroes, and would accept this as a
// 'soft' EOF. Implementations of this class do not necessarily need to
// implement this, default behavior can simply delegate to ReachedEnd().
virtual bool OnlyZeroesLeft() const {
return ReachedEnd();
}
virtual bool OnlyZeroesLeft() const { return ReachedEnd(); }
// Reads value encoded with WriteVariableWidthXXX (see BitWriterInterface).
// Reader and writer must use the same |chunk_length| and variable type.
@ -395,14 +382,14 @@ class BitReaderInterface {
bool ReadVariableWidthU32(uint32_t* val, size_t chunk_length);
bool ReadVariableWidthU16(uint16_t* val, size_t chunk_length);
bool ReadVariableWidthU8(uint8_t* val, size_t chunk_length);
bool ReadVariableWidthS64(
int64_t* val, size_t chunk_length, size_t zigzag_exponent);
bool ReadVariableWidthS32(
int32_t* val, size_t chunk_length, size_t zigzag_exponent);
bool ReadVariableWidthS16(
int16_t* val, size_t chunk_length, size_t zigzag_exponent);
bool ReadVariableWidthS8(
int8_t* val, size_t chunk_length, size_t zigzag_exponent);
bool ReadVariableWidthS64(int64_t* val, size_t chunk_length,
size_t zigzag_exponent);
bool ReadVariableWidthS32(int32_t* val, size_t chunk_length,
size_t zigzag_exponent);
bool ReadVariableWidthS16(int16_t* val, size_t chunk_length,
size_t zigzag_exponent);
bool ReadVariableWidthS8(int8_t* val, size_t chunk_length,
size_t zigzag_exponent);
// Reads value written by WriteFixedWidth (|max_val| needs to be the same).
// Returns true on success, false if the bit stream ends prematurely.
@ -428,9 +415,7 @@ class BitReaderWord64 : public BitReaderInterface {
size_t ReadBits(uint64_t* bits, size_t num_bits) override;
size_t GetNumReadBits() const override {
return pos_;
}
size_t GetNumReadBits() const override { return pos_; }
bool ReachedEnd() const override;
bool OnlyZeroesLeft() const override;
@ -445,8 +430,7 @@ class BitReaderWord64 : public BitReaderInterface {
protected:
// Sends string generated from arguments to callback_ if defined.
void EmitSequence(uint64_t bits, size_t num_bits) const {
if (callback_)
callback_(BitsToStream(bits, num_bits));
if (callback_) callback_(BitsToStream(bits, num_bits));
}
private:

View File

@ -20,11 +20,11 @@
#include <algorithm>
#include <cassert>
#include <functional>
#include <queue>
#include <iomanip>
#include <map>
#include <memory>
#include <ostream>
#include <queue>
#include <sstream>
#include <stack>
#include <tuple>
@ -74,10 +74,10 @@ class HuffmanCodec {
std::vector<uint32_t> queue_vector;
queue_vector.reserve(hist.size());
std::priority_queue<uint32_t, std::vector<uint32_t>,
std::function<bool(uint32_t, uint32_t)>>
queue(std::bind(&HuffmanCodec::LeftIsBigger, this,
std::placeholders::_1, std::placeholders::_2),
std::move(queue_vector));
std::function<bool(uint32_t, uint32_t)>>
queue(std::bind(&HuffmanCodec::LeftIsBigger, this,
std::placeholders::_1, std::placeholders::_2),
std::move(queue_vector));
// Put all leaves in the queue.
for (const auto& pair : hist) {
@ -153,11 +153,9 @@ class HuffmanCodec {
for (const Node& node : nodes_) {
code << indent2 << "{";
if (value_is_text)
code << "\"";
if (value_is_text) code << "\"";
code << node.value;
if (value_is_text)
code << "\"";
if (value_is_text) code << "\"";
code << ", " << node.left << ", " << node.right << "},\n";
}
@ -172,9 +170,7 @@ class HuffmanCodec {
// Where w stands for the weight of the node.
// Right tree branches appear above left branches. Taking the right path
// adds 1 to the code, taking the left adds 0.
void PrintTree(std::ostream& out) const {
PrintTreeInternal(out, root_, 0);
}
void PrintTree(std::ostream& out) const { PrintTreeInternal(out, root_, 0); }
// Traverses the tree and prints the Huffman table: value, code
// and optionally node weight for every leaf.
@ -188,23 +184,20 @@ class HuffmanCodec {
queue.pop();
if (!RightOf(node) && !LeftOf(node)) {
out << ValueOf(node);
if (print_weights)
out << " " << WeightOf(node);
if (print_weights) out << " " << WeightOf(node);
out << " " << code << std::endl;
} else {
if (LeftOf(node))
queue.emplace(LeftOf(node), code + "0");
if (LeftOf(node)) queue.emplace(LeftOf(node), code + "0");
if (RightOf(node))
queue.emplace(RightOf(node), code + "1");
if (RightOf(node)) queue.emplace(RightOf(node), code + "1");
}
}
}
// Returns the Huffman table. The table was built at at construction time,
// this function just returns a const reference.
const std::unordered_map<Val, std::pair<uint64_t, size_t>>&
GetEncodingTable() const {
const std::unordered_map<Val, std::pair<uint64_t, size_t>>& GetEncodingTable()
const {
return encoding_table_;
}
@ -212,8 +205,7 @@ class HuffmanCodec {
// |bits|. Returns false of |val| is not in the Huffman table.
bool Encode(const Val& val, uint64_t* bits, size_t* num_bits) const {
auto it = encoding_table_.find(val);
if (it == encoding_table_.end())
return false;
if (it == encoding_table_.end()) return false;
*bits = it->second.first;
*num_bits = it->second.second;
return true;
@ -225,8 +217,8 @@ class HuffmanCodec {
// |read_bit| has type bool func(bool* bit). When called, the next bit is
// stored in |bit|. |read_bit| returns false if the stream terminates
// prematurely.
bool DecodeFromStream(
const std::function<bool(bool*)>& read_bit, Val* val) const {
bool DecodeFromStream(const std::function<bool(bool*)>& read_bit,
Val* val) const {
uint32_t node = root_;
while (true) {
assert(node);
@ -237,8 +229,7 @@ class HuffmanCodec {
}
bool go_right;
if (!read_bit(&go_right))
return false;
if (!read_bit(&go_right)) return false;
if (go_right)
node = RightOf(node);
@ -246,35 +237,25 @@ class HuffmanCodec {
node = LeftOf(node);
}
assert (0);
assert(0);
return false;
}
private:
// Returns value of the node referenced by |handle|.
Val ValueOf(uint32_t node) const {
return nodes_.at(node).value;
}
Val ValueOf(uint32_t node) const { return nodes_.at(node).value; }
// Returns left child of |node|.
uint32_t LeftOf(uint32_t node) const {
return nodes_.at(node).left;
}
uint32_t LeftOf(uint32_t node) const { return nodes_.at(node).left; }
// Returns right child of |node|.
uint32_t RightOf(uint32_t node) const {
return nodes_.at(node).right;
}
uint32_t RightOf(uint32_t node) const { return nodes_.at(node).right; }
// Returns weight of |node|.
uint32_t WeightOf(uint32_t node) const {
return nodes_.at(node).weight;
}
uint32_t WeightOf(uint32_t node) const { return nodes_.at(node).weight; }
// Returns id of |node|.
uint32_t IdOf(uint32_t node) const {
return nodes_.at(node).id;
}
uint32_t IdOf(uint32_t node) const { return nodes_.at(node).id; }
// Returns mutable reference to value of |node|.
Val& MutableValueOf(uint32_t node) {
@ -295,20 +276,16 @@ class HuffmanCodec {
}
// Returns mutable reference to weight of |node|.
uint32_t& MutableWeightOf(uint32_t node) {
return nodes_.at(node).weight;
}
uint32_t& MutableWeightOf(uint32_t node) { return nodes_.at(node).weight; }
// Returns mutable reference to id of |node|.
uint32_t& MutableIdOf(uint32_t node) {
return nodes_.at(node).id;
}
uint32_t& MutableIdOf(uint32_t node) { return nodes_.at(node).id; }
// Returns true if |left| has bigger weight than |right|. Node ids are
// used as tie-breaker.
bool LeftIsBigger(uint32_t left, uint32_t right) const {
if (WeightOf(left) == WeightOf(right)) {
assert (IdOf(left) != IdOf(right));
assert(IdOf(left) != IdOf(right));
return IdOf(left) > IdOf(right);
}
return WeightOf(left) > WeightOf(right);
@ -316,8 +293,7 @@ class HuffmanCodec {
// Prints subtree (helper function used by PrintTree).
void PrintTreeInternal(std::ostream& out, uint32_t node, size_t depth) const {
if (!node)
return;
if (!node) return;
const size_t kTextFieldWidth = 7;
@ -348,7 +324,7 @@ class HuffmanCodec {
void CreateEncodingTable() {
struct Context {
Context(uint32_t in_node, uint64_t in_bits, size_t in_depth)
: node(in_node), bits(in_bits), depth(in_depth) {}
: node(in_node), bits(in_bits), depth(in_depth) {}
uint32_t node;
// Huffman tree depth cannot exceed 64 as histogramm counts are expected
// to be positive and limited by numeric_limits<uint32_t>::max().
@ -373,8 +349,7 @@ class HuffmanCodec {
assert(insertion_result.second);
(void)insertion_result;
} else {
if (LeftOf(node))
queue.emplace(LeftOf(node), bits, depth + 1);
if (LeftOf(node)) queue.emplace(LeftOf(node), bits, depth + 1);
if (RightOf(node))
queue.emplace(RightOf(node), bits | (1ULL << depth), depth + 1);

View File

@ -272,7 +272,7 @@ bool IntrusiveList<NodeType>::empty() const {
return sentinel_.NextNode() == nullptr;
}
template<class NodeType>
template <class NodeType>
void IntrusiveList<NodeType>::clear() {
while (!empty()) {
front().RemoveFromList();

View File

@ -110,7 +110,7 @@ template <class NodeType>
inline IntrusiveNodeBase<NodeType>::IntrusiveNodeBase()
: next_node_(nullptr), previous_node_(nullptr), is_sentinel_(false) {}
template<class NodeType>
template <class NodeType>
inline IntrusiveNodeBase<NodeType>::IntrusiveNodeBase(
const IntrusiveNodeBase&) {
next_node_ = nullptr;
@ -118,7 +118,7 @@ inline IntrusiveNodeBase<NodeType>::IntrusiveNodeBase(
is_sentinel_ = false;
}
template<class NodeType>
template <class NodeType>
inline IntrusiveNodeBase<NodeType>& IntrusiveNodeBase<NodeType>::operator=(
const IntrusiveNodeBase&) {
assert(!is_sentinel_);
@ -128,7 +128,7 @@ inline IntrusiveNodeBase<NodeType>& IntrusiveNodeBase<NodeType>::operator=(
return *this;
}
template<class NodeType>
template <class NodeType>
inline IntrusiveNodeBase<NodeType>::IntrusiveNodeBase(IntrusiveNodeBase&& that)
: next_node_(nullptr),
previous_node_(nullptr),
@ -140,19 +140,19 @@ inline IntrusiveNodeBase<NodeType>::IntrusiveNodeBase(IntrusiveNodeBase&& that)
that.ReplaceWith(this);
}
template<class NodeType>
template <class NodeType>
IntrusiveNodeBase<NodeType>::~IntrusiveNodeBase() {
assert(is_sentinel_ || !IsInAList());
}
template<class NodeType>
template <class NodeType>
IntrusiveNodeBase<NodeType>& IntrusiveNodeBase<NodeType>::operator=(
IntrusiveNodeBase&& that) {
that.ReplaceWith(this);
return *this;
}
template<class NodeType>
template <class NodeType>
inline bool IntrusiveNodeBase<NodeType>::IsInAList() const {
return next_node_ != nullptr;
}
@ -199,7 +199,7 @@ template <class NodeType>
inline void IntrusiveNodeBase<NodeType>::RemoveFromList() {
assert(!this->is_sentinel_ && "Sentinel nodes cannot be moved around.");
assert(this->IsInAList() &&
"Cannot remove a node from a list if it is not in a list.");
"Cannot remove a node from a list if it is not in a list.");
this->next_node_->previous_node_ = this->previous_node_;
this->previous_node_->next_node_ = this->next_node_;
@ -207,16 +207,16 @@ inline void IntrusiveNodeBase<NodeType>::RemoveFromList() {
this->previous_node_ = nullptr;
}
template<class NodeType>
template <class NodeType>
void IntrusiveNodeBase<NodeType>::ReplaceWith(NodeType* target) {
if (this->is_sentinel_) {
assert(target->IsEmptyList() &&
"If target is not an empty list, the nodes in that list would not "
"be linked to a sentinel.");
"If target is not an empty list, the nodes in that list would not "
"be linked to a sentinel.");
} else {
assert(IsInAList() && "The node being replaced must be in a list.");
assert(!target->is_sentinel_ &&
"Cannot turn a sentinel node into one that is not.");
"Cannot turn a sentinel node into one that is not.");
}
if (!this->IsEmptyList()) {
@ -245,13 +245,13 @@ void IntrusiveNodeBase<NodeType>::ReplaceWith(NodeType* target) {
}
}
template<class NodeType>
template <class NodeType>
bool IntrusiveNodeBase<NodeType>::IsEmptyList() {
if (next_node_ == this) {
assert(is_sentinel_ &&
"None sentinel nodes should never point to themselves.");
"None sentinel nodes should never point to themselves.");
assert(previous_node_ == this &&
"Inconsistency with the previous and next nodes.");
"Inconsistency with the previous and next nodes.");
return true;
}
return false;

View File

@ -94,16 +94,16 @@ class MoveToFront {
bool HasValue(const Val& value) const;
// Returns the number of elements in the move-to-front sequence.
uint32_t GetSize() const {
return SizeOf(root_);
}
uint32_t GetSize() const { return SizeOf(root_); }
protected:
// Internal tree data structure uses handles instead of pointers. Leaves and
// root parent reference a singleton under handle 0. Although dereferencing
// a null pointer is not possible, inappropriate access to handle 0 would
// cause an assertion. Handles are not garbage collected if value was deprecated
// with DeprecateValue(). But handles are recycled when a node is repositioned.
// cause an assertion. Handles are not garbage collected if value was
// deprecated
// with DeprecateValue(). But handles are recycled when a node is
// repositioned.
// Internal tree data structure node.
struct Node {
@ -125,7 +125,8 @@ class MoveToFront {
};
// Creates node and sets correct values. Non-NIL nodes should be created only
// through this function. If the node with this value has been created previously
// through this function. If the node with this value has been created
// previously
// and since orphaned, reuses the old node instead of creating a new one.
uint32_t CreateNode(uint32_t timestamp, const Val& value) {
uint32_t handle = static_cast<uint32_t>(nodes_.size());
@ -137,7 +138,8 @@ class MoveToFront {
node.timestamp = timestamp;
node.value = value;
node.size = 1;
// Non-NIL nodes start with height 1 because their NIL children are leaves.
// Non-NIL nodes start with height 1 because their NIL children are
// leaves.
node.height = 1;
} else {
// Reuse old node.
@ -157,24 +159,16 @@ class MoveToFront {
// ParentOf(LeftestDescendentOf(RightOf(node)))
// Returns value of the node referenced by |handle|.
Val ValueOf(uint32_t node) const {
return nodes_.at(node).value;
}
Val ValueOf(uint32_t node) const { return nodes_.at(node).value; }
// Returns left child of |node|.
uint32_t LeftOf(uint32_t node) const {
return nodes_.at(node).left;
}
uint32_t LeftOf(uint32_t node) const { return nodes_.at(node).left; }
// Returns right child of |node|.
uint32_t RightOf(uint32_t node) const {
return nodes_.at(node).right;
}
uint32_t RightOf(uint32_t node) const { return nodes_.at(node).right; }
// Returns parent of |node|.
uint32_t ParentOf(uint32_t node) const {
return nodes_.at(node).parent;
}
uint32_t ParentOf(uint32_t node) const { return nodes_.at(node).parent; }
// Returns timestamp of |node|.
uint32_t TimestampOf(uint32_t node) const {
@ -183,14 +177,10 @@ class MoveToFront {
}
// Returns size of |node|.
uint32_t SizeOf(uint32_t node) const {
return nodes_.at(node).size;
}
uint32_t SizeOf(uint32_t node) const { return nodes_.at(node).size; }
// Returns height of |node|.
uint32_t HeightOf(uint32_t node) const {
return nodes_.at(node).height;
}
uint32_t HeightOf(uint32_t node) const { return nodes_.at(node).height; }
// Returns mutable reference to value of |node|.
Val& MutableValueOf(uint32_t node) {
@ -347,8 +337,7 @@ class MultiMoveToFront {
// Removes |value| from all sequences which have it.
void RemoveFromAll(const Val& value) {
auto it = val_to_mtfs_.find(value);
if (it == val_to_mtfs_.end())
return;
if (it == val_to_mtfs_.end()) return;
auto& mtfs_containing_value = it->second;
for (uint64_t mtf : mtfs_containing_value) {
@ -371,15 +360,12 @@ class MultiMoveToFront {
}
// Returns size of |mtf| sequence.
uint32_t GetSize(uint64_t mtf) {
return GetMtf(mtf).GetSize();
}
uint32_t GetSize(uint64_t mtf) { return GetMtf(mtf).GetSize(); }
// Promotes |value| in all sequences which have it.
void Promote(const Val& value) {
const auto it = val_to_mtfs_.find(value);
if (it == val_to_mtfs_.end())
return;
if (it == val_to_mtfs_.end()) return;
const auto& mtfs_containing_value = it->second;
for (uint64_t mtf : mtfs_containing_value) {
@ -426,8 +412,7 @@ class MultiMoveToFront {
template <typename Val>
bool MoveToFront<Val>::Insert(const Val& value) {
auto it = value_to_node_.find(value);
if (it != value_to_node_.end() && IsInTree(it->second))
return false;
if (it != value_to_node_.end() && IsInTree(it->second)) return false;
const uint32_t old_size = GetSize();
(void)old_size;
@ -445,14 +430,11 @@ bool MoveToFront<Val>::Insert(const Val& value) {
template <typename Val>
bool MoveToFront<Val>::Remove(const Val& value) {
auto it = value_to_node_.find(value);
if (it == value_to_node_.end())
return false;
if (it == value_to_node_.end()) return false;
if (!IsInTree(it->second))
return false;
if (!IsInTree(it->second)) return false;
if (last_accessed_value_ == value)
last_accessed_value_valid_ = false;
if (last_accessed_value_ == value) last_accessed_value_valid_ = false;
const uint32_t orphan = RemoveNode(it->second);
(void)orphan;
@ -494,8 +476,7 @@ bool MoveToFront<Val>::RankFromValue(const Val& value, uint32_t* rank) {
uint32_t node = target;
*rank = 1 + SizeOf(LeftOf(node));
while (node) {
if (IsRightChild(node))
*rank += 1 + SizeOf(LeftOf(ParentOf(node)));
if (IsRightChild(node)) *rank += 1 + SizeOf(LeftOf(ParentOf(node)));
node = ParentOf(node);
}
@ -532,8 +513,7 @@ bool MoveToFront<Val>::Promote(const Val& value) {
}
const uint32_t old_size = GetSize();
if (old_size == 1)
return ValueOf(root_) == value;
if (old_size == 1) return ValueOf(root_) == value;
const auto it = value_to_node_.find(value);
if (it == value_to_node_.end()) {
@ -663,8 +643,7 @@ void MoveToFront<Val>::InsertNode(uint32_t node) {
// Added node to the right subtree.
if (parent_balance > 1) {
// Parent is right heavy, rotate left.
if (BalanceOf(node) < 0)
RotateRight(node);
if (BalanceOf(node) < 0) RotateRight(node);
parent = RotateLeft(parent);
} else if (parent_balance == 0 || parent_balance == -1) {
// Parent is balanced or left heavy, no need to balance further.
@ -674,8 +653,7 @@ void MoveToFront<Val>::InsertNode(uint32_t node) {
// Added node to the left subtree.
if (parent_balance < -1) {
// Parent is left heavy, rotate right.
if (BalanceOf(node) > 0)
RotateLeft(node);
if (BalanceOf(node) > 0) RotateLeft(node);
parent = RotateRight(parent);
} else if (parent_balance == 0 || parent_balance == 1) {
// Parent is balanced or right heavy, no need to balance further.
@ -695,9 +673,11 @@ template <typename Val>
uint32_t MoveToFront<Val>::RemoveNode(uint32_t node) {
if (LeftOf(node) && RightOf(node)) {
// If |node| has two children, then use another node as scapegoat and swap
// their contents. We pick the scapegoat on the side of the tree which has more nodes.
const uint32_t scapegoat = SizeOf(LeftOf(node)) >= SizeOf(RightOf(node)) ?
RightestDescendantOf(LeftOf(node)) : LeftestDescendantOf(RightOf(node));
// their contents. We pick the scapegoat on the side of the tree which has
// more nodes.
const uint32_t scapegoat = SizeOf(LeftOf(node)) >= SizeOf(RightOf(node))
? RightestDescendantOf(LeftOf(node))
: LeftestDescendantOf(RightOf(node));
assert(scapegoat);
std::swap(MutableValueOf(node), MutableValueOf(scapegoat));
std::swap(MutableTimestampOf(node), MutableTimestampOf(scapegoat));
@ -713,8 +693,7 @@ uint32_t MoveToFront<Val>::RemoveNode(uint32_t node) {
uint32_t child = RightOf(node) ? RightOf(node) : LeftOf(node);
// Orphan |node| and reconnect parent and child.
if (child)
MutableParentOf(child) = parent;
if (child) MutableParentOf(child) = parent;
if (parent) {
if (LeftOf(parent) == node)
@ -729,8 +708,7 @@ uint32_t MoveToFront<Val>::RemoveNode(uint32_t node) {
UpdateNode(node);
const uint32_t orphan = node;
if (root_ == node)
root_ = child;
if (root_ == node) root_ = child;
// Removal is finished. Start the balancing process.
bool needs_rebalancing = true;
@ -751,8 +729,7 @@ uint32_t MoveToFront<Val>::RemoveNode(uint32_t node) {
if (parent_balance < -1) {
// Parent is left heavy, rotate right.
const uint32_t sibling = LeftOf(parent);
if (BalanceOf(sibling) > 0)
RotateLeft(sibling);
if (BalanceOf(sibling) > 0) RotateLeft(sibling);
parent = RotateRight(parent);
}
} else {
@ -760,8 +737,7 @@ uint32_t MoveToFront<Val>::RemoveNode(uint32_t node) {
if (parent_balance > 1) {
// Parent is right heavy, rotate left.
const uint32_t sibling = RightOf(parent);
if (BalanceOf(sibling) < 0)
RotateRight(sibling);
if (BalanceOf(sibling) < 0) RotateRight(sibling);
parent = RotateLeft(parent);
}
}
@ -784,8 +760,7 @@ uint32_t MoveToFront<Val>::RotateLeft(const uint32_t node) {
// LeftOf(pivot) gets attached to node in place of pivot.
MutableRightOf(node) = LeftOf(pivot);
if (RightOf(node))
MutableParentOf(RightOf(node)) = node;
if (RightOf(node)) MutableParentOf(RightOf(node)) = node;
// Pivot gets attached to ParentOf(node) in place of node.
MutableParentOf(pivot) = ParentOf(node);
@ -815,8 +790,7 @@ uint32_t MoveToFront<Val>::RotateRight(const uint32_t node) {
// RightOf(pivot) gets attached to node in place of pivot.
MutableLeftOf(node) = RightOf(pivot);
if (LeftOf(node))
MutableParentOf(LeftOf(node)) = node;
if (LeftOf(node)) MutableParentOf(LeftOf(node)) = node;
// Pivot gets attached to ParentOf(node) in place of node.
MutableParentOf(pivot) = ParentOf(node);

View File

@ -68,8 +68,8 @@ EncodeNumberStatus ParseAndEncodeIntegerNumber(
const uint32_t bit_width = AssumedBitWidth(type);
if (bit_width > 64) {
ErrorMsgStream(error_msg) << "Unsupported " << bit_width
<< "-bit integer literals";
ErrorMsgStream(error_msg)
<< "Unsupported " << bit_width << "-bit integer literals";
return EncodeNumberStatus::kUnsupported;
}
@ -182,8 +182,8 @@ EncodeNumberStatus ParseAndEncodeFloatingPointNumber(
default:
break;
}
ErrorMsgStream(error_msg) << "Unsupported " << bit_width
<< "-bit float literals";
ErrorMsgStream(error_msg)
<< "Unsupported " << bit_width << "-bit float literals";
return EncodeNumberStatus::kUnsupported;
}

View File

@ -171,7 +171,7 @@ bool ParseNumber(const char* text, T* value_pointer) {
static_assert(sizeof(T) > 1,
"Single-byte types are not supported in this parse method");
if (!text) return false;
if (!text) return false;
std::istringstream text_stream(text);
// Allow both decimal and hex input for integers.
// It also allows octal input, but we don't care about that case.

View File

@ -118,7 +118,7 @@ const BasicBlock::DominatorIterator BasicBlock::pdom_begin() const {
BasicBlock::DominatorIterator BasicBlock::pdom_begin() {
return DominatorIterator(
this, [](const BasicBlock* b) { return b->immediate_post_dominator(); });
this, [](const BasicBlock* b) { return b->immediate_post_dominator(); });
}
const BasicBlock::DominatorIterator BasicBlock::pdom_end() const {

View File

@ -108,7 +108,8 @@ class BasicBlock {
void RegisterBranchInstruction(SpvOp branch_instruction);
/// Adds @p next BasicBlocks as successors of this BasicBlock
void RegisterSuccessors(const std::vector<BasicBlock*>& next = std::vector<BasicBlock*>());
void RegisterSuccessors(
const std::vector<BasicBlock*>& next = std::vector<BasicBlock*>());
/// Returns true if the id of the BasicBlock matches
bool operator==(const BasicBlock& other) const { return other.id_ == id_; }

View File

@ -19,9 +19,8 @@
namespace libspirv {
Construct::Construct(ConstructType construct_type,
BasicBlock* entry, BasicBlock* exit,
std::vector<Construct*> constructs)
Construct::Construct(ConstructType construct_type, BasicBlock* entry,
BasicBlock* exit, std::vector<Construct*> constructs)
: type_(construct_type),
corresponding_constructs_(constructs),
entry_block_(entry),
@ -38,11 +37,16 @@ std::vector<Construct*>& Construct::corresponding_constructs() {
bool ValidateConstructSize(ConstructType type, size_t size) {
switch (type) {
case ConstructType::kSelection: return size == 0;
case ConstructType::kContinue: return size == 1;
case ConstructType::kLoop: return size == 1;
case ConstructType::kCase: return size >= 1;
default: assert(1 == 0 && "Type not defined");
case ConstructType::kSelection:
return size == 0;
case ConstructType::kContinue:
return size == 1;
case ConstructType::kLoop:
return size == 1;
case ConstructType::kCase:
return size >= 1;
default:
assert(1 == 0 && "Type not defined");
}
return false;
}

View File

@ -84,4 +84,3 @@ class Decoration {
} // namespace libspirv
#endif /// LIBSPIRV_VAL_DECORATION_H_

View File

@ -17,14 +17,14 @@
#include <cassert>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include "cfa.h"
#include "val/basic_block.h"
#include "val/construct.h"
#include "validate.h"
#include "cfa.h"
using std::ignore;
using std::list;
@ -275,13 +275,9 @@ void Function::ComputeAugmentedCFG() {
auto succ_func = [](const BasicBlock* b) { return b->successors(); };
auto pred_func = [](const BasicBlock* b) { return b->predecessors(); };
spvtools::CFA<BasicBlock>::ComputeAugmentedCFG(
ordered_blocks_,
&pseudo_entry_block_,
&pseudo_exit_block_,
&augmented_successors_map_,
&augmented_predecessors_map_,
succ_func,
pred_func);
ordered_blocks_, &pseudo_entry_block_, &pseudo_exit_block_,
&augmented_successors_map_, &augmented_predecessors_map_, succ_func,
pred_func);
};
Construct& Function::AddConstruct(const Construct& new_construct) {

View File

@ -183,7 +183,8 @@ class Function {
GetBlocksFunction AugmentedCFGSuccessorsFunction() const;
/// Like AugmentedCFGSuccessorsFunction, but also includes a forward edge from
/// a loop header block to its continue target, if they are different blocks.
GetBlocksFunction AugmentedCFGSuccessorsFunctionIncludingHeaderToContinueEdge() const;
GetBlocksFunction
AugmentedCFGSuccessorsFunctionIncludingHeaderToContinueEdge() const;
/// Returns the block predecessors function for the augmented CFG.
GetBlocksFunction AugmentedCFGPredecessorsFunction() const;

View File

@ -72,9 +72,7 @@ class Instruction {
}
/// Provides direct access to the stored C instruction object.
const spv_parsed_instruction_t& c_inst() const {
return inst_;
}
const spv_parsed_instruction_t& c_inst() const { return inst_; }
// Casts the words belonging to the operand under |index| to |T| and returns.
template <typename T>

View File

@ -358,15 +358,14 @@ class ValidationState_t {
// Provides detailed information on matrix type.
// Returns false iff |id| is not matrix type.
bool GetMatrixTypeInfo(
uint32_t id, uint32_t* num_rows, uint32_t* num_cols,
uint32_t* column_type, uint32_t* component_type) const;
bool GetMatrixTypeInfo(uint32_t id, uint32_t* num_rows, uint32_t* num_cols,
uint32_t* column_type, uint32_t* component_type) const;
// Collects struct member types into |member_types|.
// Returns false iff not struct type or has no members.
// Deletes prior contents of |member_types|.
bool GetStructMemberTypes(
uint32_t struct_type_id, std::vector<uint32_t>* member_types) const;
bool GetStructMemberTypes(uint32_t struct_type_id,
std::vector<uint32_t>* member_types) const;
// Returns true iff |id| is a type corresponding to the name of the function.
// Only works for types not for objects.
@ -393,8 +392,8 @@ class ValidationState_t {
size_t operand_index) const;
// Provides information on pointer type. Returns false iff not pointer type.
bool GetPointerTypeInfo(
uint32_t id, uint32_t* data_type, uint32_t* storage_class) const;
bool GetPointerTypeInfo(uint32_t id, uint32_t* data_type,
uint32_t* storage_class) const;
private:
ValidationState_t(const ValidationState_t&);

Some files were not shown because too many files have changed in this diff Show More