1b8e80941Smrg/*
2b8e80941Smrg * Copyright © 2011 Intel Corporation
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21b8e80941Smrg * DEALINGS IN THE SOFTWARE.
22b8e80941Smrg */
23b8e80941Smrg
24b8e80941Smrg/**
25b8e80941Smrg * \file test_optpass.cpp
26b8e80941Smrg *
27b8e80941Smrg * Standalone test for optimization passes.
28b8e80941Smrg *
29b8e80941Smrg * This file provides the "optpass" command for the standalone
30b8e80941Smrg * glsl_test app.  It accepts either GLSL or high-level IR as input,
31b8e80941Smrg * and performs the optimiation passes specified on the command line.
32b8e80941Smrg * It outputs the IR, both before and after optimiations.
33b8e80941Smrg */
34b8e80941Smrg
35b8e80941Smrg#include <string>
36b8e80941Smrg#include <iostream>
37b8e80941Smrg#include <sstream>
38b8e80941Smrg#include <getopt.h>
39b8e80941Smrg
40b8e80941Smrg#include "ast.h"
41b8e80941Smrg#include "ir_optimization.h"
42b8e80941Smrg#include "program.h"
43b8e80941Smrg#include "ir_reader.h"
44b8e80941Smrg#include "standalone_scaffolding.h"
45b8e80941Smrg#include "main/mtypes.h"
46b8e80941Smrg
47b8e80941Smrgusing namespace std;
48b8e80941Smrg
49b8e80941Smrgstatic string read_stdin_to_eof()
50b8e80941Smrg{
51b8e80941Smrg   stringbuf sb;
52b8e80941Smrg   cin.get(sb, '\0');
53b8e80941Smrg   return sb.str();
54b8e80941Smrg}
55b8e80941Smrg
56b8e80941Smrgstatic GLboolean
57b8e80941Smrgdo_optimization(struct exec_list *ir, const char *optimization,
58b8e80941Smrg                const struct gl_shader_compiler_options *options)
59b8e80941Smrg{
60b8e80941Smrg   int int_0;
61b8e80941Smrg   int int_1;
62b8e80941Smrg   int int_2;
63b8e80941Smrg   int int_3;
64b8e80941Smrg   int int_4;
65b8e80941Smrg
66b8e80941Smrg   if (sscanf(optimization, "do_common_optimization ( %d ) ", &int_0) == 1) {
67b8e80941Smrg      return do_common_optimization(ir, int_0 != 0, false, options, true);
68b8e80941Smrg   } else if (strcmp(optimization, "do_algebraic") == 0) {
69b8e80941Smrg      return do_algebraic(ir, true, options);
70b8e80941Smrg   } else if (strcmp(optimization, "do_constant_folding") == 0) {
71b8e80941Smrg      return do_constant_folding(ir);
72b8e80941Smrg   } else if (strcmp(optimization, "do_constant_variable") == 0) {
73b8e80941Smrg      return do_constant_variable(ir);
74b8e80941Smrg   } else if (strcmp(optimization, "do_constant_variable_unlinked") == 0) {
75b8e80941Smrg      return do_constant_variable_unlinked(ir);
76b8e80941Smrg   } else if (strcmp(optimization, "do_copy_propagation_elements") == 0) {
77b8e80941Smrg      return do_copy_propagation_elements(ir);
78b8e80941Smrg   } else if (strcmp(optimization, "do_constant_propagation") == 0) {
79b8e80941Smrg      return do_constant_propagation(ir);
80b8e80941Smrg   } else if (strcmp(optimization, "do_dead_code") == 0) {
81b8e80941Smrg      return do_dead_code(ir, false);
82b8e80941Smrg   } else if (strcmp(optimization, "do_dead_code_local") == 0) {
83b8e80941Smrg      return do_dead_code_local(ir);
84b8e80941Smrg   } else if (strcmp(optimization, "do_dead_code_unlinked") == 0) {
85b8e80941Smrg      return do_dead_code_unlinked(ir);
86b8e80941Smrg   } else if (strcmp(optimization, "do_dead_functions") == 0) {
87b8e80941Smrg      return do_dead_functions(ir);
88b8e80941Smrg   } else if (strcmp(optimization, "do_function_inlining") == 0) {
89b8e80941Smrg      return do_function_inlining(ir);
90b8e80941Smrg   } else if (sscanf(optimization,
91b8e80941Smrg                     "do_lower_jumps ( %d , %d , %d , %d , %d ) ",
92b8e80941Smrg                     &int_0, &int_1, &int_2, &int_3, &int_4) == 5) {
93b8e80941Smrg      return do_lower_jumps(ir, int_0 != 0, int_1 != 0, int_2 != 0,
94b8e80941Smrg                            int_3 != 0, int_4 != 0);
95b8e80941Smrg   } else if (strcmp(optimization, "do_lower_texture_projection") == 0) {
96b8e80941Smrg      return do_lower_texture_projection(ir);
97b8e80941Smrg   } else if (strcmp(optimization, "do_if_simplification") == 0) {
98b8e80941Smrg      return do_if_simplification(ir);
99b8e80941Smrg   } else if (sscanf(optimization, "lower_if_to_cond_assign ( %d ) ",
100b8e80941Smrg                     &int_0) == 1) {
101b8e80941Smrg      return lower_if_to_cond_assign(MESA_SHADER_VERTEX, ir, int_0);
102b8e80941Smrg   } else if (strcmp(optimization, "do_mat_op_to_vec") == 0) {
103b8e80941Smrg      return do_mat_op_to_vec(ir);
104b8e80941Smrg   } else if (strcmp(optimization, "optimize_swizzles") == 0) {
105b8e80941Smrg      return optimize_swizzles(ir);
106b8e80941Smrg   } else if (strcmp(optimization, "do_structure_splitting") == 0) {
107b8e80941Smrg      return do_structure_splitting(ir);
108b8e80941Smrg   } else if (strcmp(optimization, "do_tree_grafting") == 0) {
109b8e80941Smrg      return do_tree_grafting(ir);
110b8e80941Smrg   } else if (strcmp(optimization, "do_vec_index_to_cond_assign") == 0) {
111b8e80941Smrg      return do_vec_index_to_cond_assign(ir);
112b8e80941Smrg   } else if (strcmp(optimization, "do_vec_index_to_swizzle") == 0) {
113b8e80941Smrg      return do_vec_index_to_swizzle(ir);
114b8e80941Smrg   } else if (strcmp(optimization, "lower_discard") == 0) {
115b8e80941Smrg      return lower_discard(ir);
116b8e80941Smrg   } else if (sscanf(optimization, "lower_instructions ( %d ) ",
117b8e80941Smrg                     &int_0) == 1) {
118b8e80941Smrg      return lower_instructions(ir, int_0);
119b8e80941Smrg   } else if (strcmp(optimization, "lower_noise") == 0) {
120b8e80941Smrg      return lower_noise(ir);
121b8e80941Smrg   } else if (sscanf(optimization, "lower_variable_index_to_cond_assign "
122b8e80941Smrg                     "( %d , %d , %d , %d ) ", &int_0, &int_1, &int_2,
123b8e80941Smrg                     &int_3) == 4) {
124b8e80941Smrg      return lower_variable_index_to_cond_assign(MESA_SHADER_VERTEX, ir,
125b8e80941Smrg                                                 int_0 != 0, int_1 != 0,
126b8e80941Smrg                                                 int_2 != 0, int_3 != 0);
127b8e80941Smrg   } else if (sscanf(optimization, "lower_quadop_vector ( %d ) ",
128b8e80941Smrg                     &int_0) == 1) {
129b8e80941Smrg      return lower_quadop_vector(ir, int_0 != 0);
130b8e80941Smrg   } else if (strcmp(optimization, "optimize_redundant_jumps") == 0) {
131b8e80941Smrg      return optimize_redundant_jumps(ir);
132b8e80941Smrg   } else {
133b8e80941Smrg      printf("Unrecognized optimization %s\n", optimization);
134b8e80941Smrg      exit(EXIT_FAILURE);
135b8e80941Smrg      return false;
136b8e80941Smrg   }
137b8e80941Smrg}
138b8e80941Smrg
139b8e80941Smrgstatic GLboolean
140b8e80941Smrgdo_optimization_passes(struct exec_list *ir, char **optimizations,
141b8e80941Smrg                       int num_optimizations, bool quiet,
142b8e80941Smrg                       const struct gl_shader_compiler_options *options)
143b8e80941Smrg{
144b8e80941Smrg   GLboolean overall_progress = false;
145b8e80941Smrg
146b8e80941Smrg   for (int i = 0; i < num_optimizations; ++i) {
147b8e80941Smrg      const char *optimization = optimizations[i];
148b8e80941Smrg      if (!quiet) {
149b8e80941Smrg         printf("*** Running optimization %s...", optimization);
150b8e80941Smrg      }
151b8e80941Smrg      GLboolean progress = do_optimization(ir, optimization, options);
152b8e80941Smrg      if (!quiet) {
153b8e80941Smrg         printf("%s\n", progress ? "progress" : "no progress");
154b8e80941Smrg      }
155b8e80941Smrg      validate_ir_tree(ir);
156b8e80941Smrg
157b8e80941Smrg      overall_progress = overall_progress || progress;
158b8e80941Smrg   }
159b8e80941Smrg
160b8e80941Smrg   return overall_progress;
161b8e80941Smrg}
162b8e80941Smrg
163b8e80941Smrgint test_optpass(int argc, char **argv)
164b8e80941Smrg{
165b8e80941Smrg   int input_format_ir = 0; /* 0=glsl, 1=ir */
166b8e80941Smrg   int loop = 0;
167b8e80941Smrg   int shader_type = GL_VERTEX_SHADER;
168b8e80941Smrg   int quiet = 0;
169b8e80941Smrg   int error;
170b8e80941Smrg
171b8e80941Smrg   const struct option optpass_opts[] = {
172b8e80941Smrg      { "input-ir", no_argument, &input_format_ir, 1 },
173b8e80941Smrg      { "input-glsl", no_argument, &input_format_ir, 0 },
174b8e80941Smrg      { "loop", no_argument, &loop, 1 },
175b8e80941Smrg      { "vertex-shader", no_argument, &shader_type, GL_VERTEX_SHADER },
176b8e80941Smrg      { "fragment-shader", no_argument, &shader_type, GL_FRAGMENT_SHADER },
177b8e80941Smrg      { "quiet", no_argument, &quiet, 1 },
178b8e80941Smrg      { NULL, 0, NULL, 0 }
179b8e80941Smrg   };
180b8e80941Smrg
181b8e80941Smrg   int idx = 0;
182b8e80941Smrg   int c;
183b8e80941Smrg   while ((c = getopt_long(argc, argv, "", optpass_opts, &idx)) != -1) {
184b8e80941Smrg      if (c != 0) {
185b8e80941Smrg         printf("*** usage: %s optpass <optimizations> <options>\n", argv[0]);
186b8e80941Smrg         printf("\n");
187b8e80941Smrg         printf("Possible options are:\n");
188b8e80941Smrg         printf("  --input-ir: input format is IR\n");
189b8e80941Smrg         printf("  --input-glsl: input format is GLSL (the default)\n");
190b8e80941Smrg         printf("  --loop: run optimizations repeatedly until no progress\n");
191b8e80941Smrg         printf("  --vertex-shader: test with a vertex shader (the default)\n");
192b8e80941Smrg         printf("  --fragment-shader: test with a fragment shader\n");
193b8e80941Smrg         exit(EXIT_FAILURE);
194b8e80941Smrg      }
195b8e80941Smrg   }
196b8e80941Smrg
197b8e80941Smrg   struct gl_context local_ctx;
198b8e80941Smrg   struct gl_context *ctx = &local_ctx;
199b8e80941Smrg   initialize_context_to_defaults(ctx, API_OPENGL_COMPAT);
200b8e80941Smrg
201b8e80941Smrg   ir_variable::temporaries_allocate_names = true;
202b8e80941Smrg
203b8e80941Smrg   struct gl_shader *shader = rzalloc(NULL, struct gl_shader);
204b8e80941Smrg   shader->Type = shader_type;
205b8e80941Smrg   shader->Stage = _mesa_shader_enum_to_shader_stage(shader_type);
206b8e80941Smrg
207b8e80941Smrg   string input = read_stdin_to_eof();
208b8e80941Smrg
209b8e80941Smrg   struct _mesa_glsl_parse_state *state
210b8e80941Smrg      = new(shader) _mesa_glsl_parse_state(ctx, shader->Stage, shader);
211b8e80941Smrg
212b8e80941Smrg   if (input_format_ir) {
213b8e80941Smrg      shader->ir = new(shader) exec_list;
214b8e80941Smrg      _mesa_glsl_initialize_types(state);
215b8e80941Smrg      _mesa_glsl_read_ir(state, shader->ir, input.c_str(), true);
216b8e80941Smrg   } else {
217b8e80941Smrg      shader->Source = input.c_str();
218b8e80941Smrg      const char *source = shader->Source;
219b8e80941Smrg      state->error = glcpp_preprocess(state, &source, &state->info_log,
220b8e80941Smrg                                      NULL, NULL, ctx) != 0;
221b8e80941Smrg
222b8e80941Smrg      if (!state->error) {
223b8e80941Smrg         _mesa_glsl_lexer_ctor(state, source);
224b8e80941Smrg         _mesa_glsl_parse(state);
225b8e80941Smrg         _mesa_glsl_lexer_dtor(state);
226b8e80941Smrg      }
227b8e80941Smrg
228b8e80941Smrg      shader->ir = new(shader) exec_list;
229b8e80941Smrg      if (!state->error && !state->translation_unit.is_empty())
230b8e80941Smrg         _mesa_ast_to_hir(shader->ir, state);
231b8e80941Smrg   }
232b8e80941Smrg
233b8e80941Smrg   /* Print out the initial IR */
234b8e80941Smrg   if (!state->error && !quiet) {
235b8e80941Smrg      printf("*** pre-optimization IR:\n");
236b8e80941Smrg      _mesa_print_ir(stdout, shader->ir, state);
237b8e80941Smrg      printf("\n--\n");
238b8e80941Smrg   }
239b8e80941Smrg
240b8e80941Smrg   /* Optimization passes */
241b8e80941Smrg   if (!state->error) {
242b8e80941Smrg      GLboolean progress;
243b8e80941Smrg      const struct gl_shader_compiler_options *options =
244b8e80941Smrg         &ctx->Const.ShaderCompilerOptions[_mesa_shader_enum_to_shader_stage(shader_type)];
245b8e80941Smrg      do {
246b8e80941Smrg         progress = do_optimization_passes(shader->ir, &argv[optind],
247b8e80941Smrg                                           argc - optind, quiet != 0, options);
248b8e80941Smrg      } while (loop && progress);
249b8e80941Smrg   }
250b8e80941Smrg
251b8e80941Smrg   /* Print out the resulting IR */
252b8e80941Smrg   if (!state->error) {
253b8e80941Smrg      if (!quiet) {
254b8e80941Smrg         printf("*** resulting IR:\n");
255b8e80941Smrg      }
256b8e80941Smrg      _mesa_print_ir(stdout, shader->ir, state);
257b8e80941Smrg      if (!quiet) {
258b8e80941Smrg         printf("\n--\n");
259b8e80941Smrg      }
260b8e80941Smrg   }
261b8e80941Smrg
262b8e80941Smrg   if (state->error) {
263b8e80941Smrg      printf("*** error(s) occurred:\n");
264b8e80941Smrg      printf("%s\n", state->info_log);
265b8e80941Smrg      printf("--\n");
266b8e80941Smrg   }
267b8e80941Smrg
268b8e80941Smrg   error = state->error;
269b8e80941Smrg
270b8e80941Smrg   ralloc_free(state);
271b8e80941Smrg   ralloc_free(shader);
272b8e80941Smrg
273b8e80941Smrg   return error;
274b8e80941Smrg}
275b8e80941Smrg
276