@@ -75,27 +75,20 @@ class PassTest : public TestT {
7575 disassemble_options_ (SpirvTools::kDefaultDisassembleOption ),
7676 env_ (SPV_ENV_UNIVERSAL_1_3) {}
7777
78- // Runs the given |pass| on the binary assembled from the |original|.
79- // Returns a tuple of the optimized binary and the boolean value returned
80- // from pass Process() function.
81- std::tuple<std::vector<uint32_t >, Pass::Status> OptimizeToBinary (
82- Pass* pass, const std::string& original, bool skip_nop) {
83- context_ = BuildModule (env_, consumer_, original, assemble_options_);
84- EXPECT_NE (nullptr , context ()) << " Assembling failed for shader:\n "
85- << original << std::endl;
86- if (!context ()) {
87- return std::make_tuple (std::vector<uint32_t >(), Pass::Status::Failure);
88- }
89-
90- context ()->set_preserve_bindings (OptimizerOptions ()->preserve_bindings_ );
91- context ()->set_preserve_spec_constants (
78+ // Runs the given |pass| on the given |context|. Returns a tuple of the
79+ // optimized binary and the boolean value returned from pass Process()
80+ // function.
81+ std::tuple<std::vector<uint32_t >, Pass::Status> RunPassAndGetBinary (
82+ Pass* pass, IRContext* context, bool skip_nop) {
83+ context->set_preserve_bindings (OptimizerOptions ()->preserve_bindings_ );
84+ context->set_preserve_spec_constants (
9285 OptimizerOptions ()->preserve_spec_constants_ );
9386
94- const auto status = pass->Run (context () );
87+ const auto status = pass->Run (context);
9588
9689 std::vector<uint32_t > binary;
9790 if (status != Pass::Status::Failure) {
98- context () ->module ()->ToBinary (&binary, skip_nop);
91+ context->module ()->ToBinary (&binary, skip_nop);
9992 }
10093 return std::make_tuple (binary, status);
10194 }
@@ -106,9 +99,71 @@ class PassTest : public TestT {
10699 template <typename PassT, typename ... Args>
107100 std::tuple<std::vector<uint32_t >, Pass::Status> SinglePassRunToBinary (
108101 const std::string& assembly, bool skip_nop, Args&&... args) {
109- auto pass = MakeUnique<PassT>(std::forward<Args>(args)...);
102+ // Copy the arguments so they can be used to create two instances of the
103+ // pass.
104+ std::tuple<std::decay_t <Args>...> copied_args (std::forward<Args>(args)...);
105+
106+ auto pass = std::apply (
107+ [&](const auto &... an_arg) { return MakeUnique<PassT>(an_arg...); },
108+ copied_args);
110109 pass->SetMessageConsumer (consumer_);
111- return OptimizeToBinary (pass.get (), assembly, skip_nop);
110+
111+ context_ = BuildModule (env_, consumer_, assembly, assemble_options_);
112+ EXPECT_NE (nullptr , context ()) << " Assembling failed for shader:\n "
113+ << assembly << std::endl;
114+ if (!context ()) {
115+ return std::make_tuple (std::vector<uint32_t >(), Pass::Status::Failure);
116+ }
117+
118+ const uint32_t original_id_bound = context ()->module ()->id_bound ();
119+
120+ auto result = RunPassAndGetBinary (pass.get (), context_.get (), skip_nop);
121+
122+ const uint32_t optimized_id_bound = context ()->module ()->id_bound ();
123+
124+ // Second run (if needed) to test for id overflow.
125+ if (std::get<1 >(result) == Pass::Status::SuccessWithChange) {
126+ for (uint32_t new_bound = original_id_bound;
127+ new_bound < optimized_id_bound; ++new_bound) {
128+ auto null_message_consumer = [](spv_message_level_t , const char *,
129+ const spv_position_t &, const char *) {};
130+ std::unique_ptr<IRContext> context2 = BuildModule (
131+ env_, null_message_consumer, assembly, assemble_options_);
132+ EXPECT_NE (nullptr , context2)
133+ << " Assembling failed for shader (2nd run):\n "
134+ << assembly << std::endl;
135+ if (context2) {
136+ auto pass2 = std::apply (
137+ [&](const auto &... an_arg) {
138+ return MakeUnique<PassT>(an_arg...);
139+ },
140+ copied_args);
141+ pass2->SetMessageConsumer (null_message_consumer);
142+
143+ // const uint32_t new_bound = (original_id_bound + optimized_id_bound)
144+ // / 2;
145+ context2->set_max_id_bound (new_bound);
146+
147+ // We don't care about the status, just that it doesn't crash.
148+ (void )RunPassAndGetBinary (pass2.get (), context2.get (), skip_nop);
149+ }
150+ }
151+ }
152+ return result;
153+ }
154+
155+ // Runs the given |pass| on the binary assembled from the |original|.
156+ // Returns a tuple of the optimized binary and the boolean value returned
157+ // from pass Process() function.
158+ std::tuple<std::vector<uint32_t >, Pass::Status> OptimizeToBinary (
159+ Pass* pass, const std::string& original, bool skip_nop) {
160+ context_ = BuildModule (env_, consumer_, original, assemble_options_);
161+ EXPECT_NE (nullptr , context ()) << " Assembling failed for shader:\n "
162+ << original << std::endl;
163+ if (!context ()) {
164+ return std::make_tuple (std::vector<uint32_t >(), Pass::Status::Failure);
165+ }
166+ return RunPassAndGetBinary (pass, context_.get (), skip_nop);
112167 }
113168
114169 // Runs a single pass of class |PassT| on the binary assembled from the
@@ -152,31 +207,15 @@ class PassTest : public TestT {
152207 void SinglePassRunAndCheck (const std::string& original,
153208 const std::string& expected, bool skip_nop,
154209 bool do_validation, Args&&... args) {
155- std::vector<uint32_t > optimized_bin;
156- auto status = Pass::Status::SuccessWithoutChange;
157- std::tie (optimized_bin, status) = SinglePassRunToBinary<PassT>(
158- original, skip_nop, std::forward<Args>(args)...);
210+ std::string optimized_asm;
211+ Pass::Status status;
212+ std::tie (optimized_asm, status) = SinglePassRunAndDisassemble<PassT>(
213+ original, skip_nop, do_validation, std::forward<Args>(args)...);
214+
159215 // Check whether the pass returns the correct modification indication.
160216 EXPECT_NE (Pass::Status::Failure, status);
161217 EXPECT_EQ (original == expected,
162218 status == Pass::Status::SuccessWithoutChange);
163- if (do_validation) {
164- spv_context spvContext = spvContextCreate (env_);
165- spv_diagnostic diagnostic = nullptr ;
166- spv_const_binary_t binary = {optimized_bin.data (), optimized_bin.size ()};
167- spv_result_t error = spvValidateWithOptions (
168- spvContext, ValidatorOptions (), &binary, &diagnostic);
169- EXPECT_EQ (error, 0 );
170- if (error != 0 ) spvDiagnosticPrint (diagnostic);
171- spvDiagnosticDestroy (diagnostic);
172- spvContextDestroy (spvContext);
173- }
174- std::string optimized_asm;
175- SpirvTools tools (env_);
176- EXPECT_TRUE (
177- tools.Disassemble (optimized_bin, &optimized_asm, disassemble_options_))
178- << " Disassembling failed for shader:\n "
179- << original << std::endl;
180219 EXPECT_EQ (expected, optimized_asm);
181220 }
182221
0 commit comments