#define SPIRV_TOOLS_OPTIMIZER_HPP_
#include <memory>
+#include <ostream>
#include <string>
#include <unordered_map>
#include <vector>
// pass manager is destroyed.
std::vector<const char*> GetPassNames() const;
+ // Sets the option to print the disassembly before each pass and after the
+ // last pass. If |out| is null, then no output is generated. Otherwise,
+ // output is sent to the |out| output stream.
+ Optimizer& SetPrintAll(std::ostream* out);
+
private:
struct Impl; // Opaque struct for holding internal data.
std::unique_ptr<Impl> impl_; // Unique pointer to internal data.
return status != opt::Pass::Status::Failure;
}
+Optimizer& Optimizer::SetPrintAll(std::ostream* out) {
+ impl_->pass_manager.SetPrintAll(out);
+ return *this;
+}
+
Optimizer::PassToken CreateNullPass() {
return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
}
// limitations under the License.
#include "pass_manager.h"
+
+#include <iostream>
+#include <vector>
+
#include "ir_context.h"
+#include "spirv-tools/libspirv.hpp"
namespace spvtools {
+
namespace opt {
Pass::Status PassManager::Run(ir::IRContext* context) {
auto status = Pass::Status::SuccessWithoutChange;
+
+ // If print_all_stream_ is not null, prints the disassembly of the module
+ // to that stream, with the given preamble and optionally the pass name.
+ auto print_disassembly = [&context, this](const char* preamble, Pass* pass) {
+ if (print_all_stream_) {
+ std::vector<uint32_t> binary;
+ context->module()->ToBinary(&binary, false);
+ SpirvTools t(SPV_ENV_UNIVERSAL_1_2);
+ std::string disassembly;
+ t.Disassemble(binary, &disassembly, 0);
+ *print_all_stream_ << preamble << (pass ? pass->name() : "") << "\n"
+ << disassembly << std::endl;
+ }
+ };
+
for (const auto& pass : passes_) {
+ print_disassembly("; IR before pass ", pass.get());
const auto one_status = pass->Run(context);
if (one_status == Pass::Status::Failure) return one_status;
if (one_status == Pass::Status::SuccessWithChange) status = one_status;
}
+ print_disassembly("; IR after last pass", nullptr);
// Set the Id bound in the header in case a pass forgot to do so.
//
#define LIBSPIRV_OPT_PASS_MANAGER_H_
#include <memory>
+#include <ostream>
#include <vector>
#include "log.h"
// The constructed instance will have an empty message consumer, which just
// ignores all messages from the library. Use SetMessageConsumer() to supply
// one if messages are of concern.
- PassManager() : consumer_(nullptr) {}
+ PassManager() : consumer_(nullptr), print_all_stream_(nullptr) {}
// Sets the message consumer to the given |consumer|.
void SetMessageConsumer(MessageConsumer c) { consumer_ = std::move(c); }
// After running all the passes, they are removed from the list.
Pass::Status Run(ir::IRContext* context);
+ // Sets the option to print the disassembly before each pass and after the
+ // last pass. Output is written to |out| if that is not null. No output
+ // is generated if |out| is null.
+ PassManager& SetPrintAll(std::ostream* out) {
+ print_all_stream_ = out;
+ return *this;
+ }
+
private:
// Consumer for messages.
MessageConsumer consumer_;
// A vector of passes. Order matters.
std::vector<std::unique_ptr<Pass>> passes_;
+ // The output stream to write disassembly to before each pass, and after
+ // the last pass. If this is null, no output is generated.
+ std::ostream* print_all_stream_;
};
inline void PassManager::AddPass(std::unique_ptr<Pass> pass) {
'spirv-opt --merge-blocks -O ...' applies the transformation
--merge-blocks followed by all the transformations implied by
-O.
+ --print-all
+ Print SPIR-V assembly to standard error output before each pass
+ and after the last pass.
--private-to-local
Change the scope of private variables that are used in a single
function to that function.
}
} else if (0 == strcmp(cur_arg, "--ccp")) {
optimizer->RegisterPass(CreateCCPPass());
+ } else if (0 == strcmp(cur_arg, "--print-all")) {
+ optimizer->SetPrintAll(&std::cerr);
} else if ('\0' == cur_arg[1]) {
// Setting a filename of "-" to indicate stdin.
if (!*in_file) {