SPIRV-Tools/source/opt/instruction_list.h
Steven Perron 65046eca7c Change IRContext::KillInst to delete instructions.
The current method of removing an instruction is to call ToNop.  The
problem with this is that it leaves around an instruction that later
passes will look at.  We should just delete the instruction.

In MemPass there is a utility routine called DCEInst.  It can delete
essentially any instruction, which can invalidate pointers now that they
are actually deleted.  The interface was changed to add a call back that
can be used to update any local data structures that contain
ir::Intruction*.
2017-12-04 11:07:45 -05:00

132 lines
4.5 KiB
C++

// Copyright (c) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef LIBSPIRV_OPT_INSTRUCTION_LIST_H_
#define LIBSPIRV_OPT_INSTRUCTION_LIST_H_
#include <cassert>
#include <functional>
#include <utility>
#include <vector>
#include "instruction.h"
#include "operand.h"
#include "util/ilist.h"
#include "spirv-tools/libspirv.h"
#include "spirv/1.2/spirv.h"
namespace spvtools {
namespace ir {
// This class is intended to be the container for Instructions. This container
// owns the instructions that are in it. When removing an Instruction from the
// list, the caller is assuming responsibility for deleting the storage.
//
// TODO: Because there are a number of other data structures that will want
// pointers to instruction, ownership should probably be moved to the module.
// Because of that I have not made the ownership passing in this class fully
// explicit. For example, RemoveFromList takes ownership from the list, but
// does not return an std::unique_ptr to signal that. When we fully decide on
// ownership, this will have to be fixed up one way or the other.
class InstructionList : public utils::IntrusiveList<Instruction> {
public:
InstructionList() = default;
InstructionList(InstructionList&& that)
: utils::IntrusiveList<Instruction>(std::move(that)) {}
InstructionList& operator=(InstructionList&& that) {
auto p = static_cast<utils::IntrusiveList<Instruction>*>(this);
*p = std::move(that);
return *this;
}
// Destroy this list and any instructions in the list.
inline virtual ~InstructionList();
class iterator : public utils::IntrusiveList<Instruction>::iterator {
public:
iterator(const utils::IntrusiveList<Instruction>::iterator& i)
: utils::IntrusiveList<Instruction>::iterator(i) {}
iterator(Instruction* i) : utils::IntrusiveList<Instruction>::iterator(i) {}
// DEPRECATED: Please use MoveBefore with an InstructionList instead.
//
// Moves the nodes in |list| to the list that |this| points to. The
// positions of the nodes will be immediately before the element pointed to
// by the iterator. The return value will be an iterator pointing to the
// first of the newly inserted elements. Ownership of the elements in
// |list| is now passed on to |*this|.
iterator InsertBefore(std::vector<std::unique_ptr<Instruction>>&& list);
// The node |i| will be inserted immediately before |this|. The return value
// will be an iterator pointing to the newly inserted node. The owner of
// |*i| becomes |*this|
iterator InsertBefore(std::unique_ptr<Instruction>&& i);
// Removes the node from the list, and deletes the storage. Returns a valid
// iterator to the next node.
iterator Erase() {
iterator_template next_node = *this;
++next_node;
node_->RemoveFromList();
delete node_;
return next_node;
}
};
iterator begin() { return utils::IntrusiveList<Instruction>::begin(); }
iterator end() { return utils::IntrusiveList<Instruction>::end(); }
const_iterator begin() const {
return utils::IntrusiveList<Instruction>::begin();
}
const_iterator end() const {
return utils::IntrusiveList<Instruction>::end();
}
void push_back(std::unique_ptr<Instruction>&& inst) {
utils::IntrusiveList<Instruction>::push_back(inst.release());
}
// Same as in the base class, except it will delete the data as well.
inline void clear();
// Runs the given function |f| on the instructions in the list and optionally
// on the preceding debug line instructions.
inline void ForEachInst(
const std::function<void(Instruction*)>& f,
bool run_on_debug_line_insts) {
auto next = begin();
for( auto i = next; i != end(); i = next ) {
++next;
i->ForEachInst(f, run_on_debug_line_insts);
}
}
};
InstructionList::~InstructionList() { clear(); }
void InstructionList::clear() {
while (!empty()) {
Instruction* inst = &front();
inst->RemoveFromList();
delete inst;
}
}
} // namespace ir
} // namespace spvtools
#endif // LIBSPIRV_OPT_INSTRUCTION_LIST_H_