Flutter Engine
The Flutter Engine
SkSLTransform.h
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google LLC.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SKSL_TRANSFORM
9#define SKSL_TRANSFORM
10
11#include "include/core/SkSpan.h"
13
14#include <memory>
15#include <vector>
16
17namespace SkSL {
18
19class Context;
20class Expression;
21class IndexExpression;
22struct Module;
23struct Program;
24class ProgramElement;
25class ProgramUsage;
26class Statement;
27class SwitchStatement;
28class Variable;
29enum class ProgramKind : int8_t;
30
31namespace Transform {
32
33/**
34 * Checks to see if it would be safe to add `const` to the modifier flags of a variable. If so,
35 * returns the modifiers with `const` applied; if not, returns the existing modifiers as-is. Adding
36 * `const` allows the inliner to fold away more values and generate tighter code.
37 */
38ModifierFlags AddConstToVarModifiers(const Variable& var,
39 const Expression* initialValue,
40 const ProgramUsage* usage);
41
42/**
43 * Rewrites indexed swizzles of the form `myVec.zyx[i]` by replacing the swizzle with a lookup into
44 * a constant vector. e.g., the above expression would be rewritten as `myVec[vec3(2, 1, 0)[i]]`.
45 * This roughly matches glslang's handling of the code.
46 */
47std::unique_ptr<Expression> RewriteIndexedSwizzle(const Context& context,
48 const IndexExpression& swizzle);
49
50/**
51 * Copies built-in functions from modules into the program. Relies on ProgramUsage to determine
52 * which functions are necessary.
53 */
54void FindAndDeclareBuiltinFunctions(Program& program);
55
56/**
57 * Copies built-in structs from modules into the program. Relies on ProgramUsage to determine
58 * which structs are necessary.
59 */
60void FindAndDeclareBuiltinStructs(Program& program);
61
62/**
63 * Scans the finished program for built-in variables like `sk_FragColor` and adds them to the
64 * program's shared elements.
65 */
66void FindAndDeclareBuiltinVariables(Program& program);
67
68/**
69 * Eliminates statements in a block which cannot be reached; for example, a statement
70 * immediately after a `return` or `continue` can safely be eliminated.
71 */
72void EliminateUnreachableCode(Module& module, ProgramUsage* usage);
73void EliminateUnreachableCode(Program& program);
74
75/**
76 * Eliminates empty statements in a module (Nops, or blocks holding only Nops). Not implemented for
77 * Programs because Nops are harmless, but they waste space in long-lived module IR.
78 */
79void EliminateEmptyStatements(Module& module);
80
81/**
82 * Eliminates unnecessary braces in a module (e.g., single-statement child blocks). Not implemented
83 * for Programs because extra braces are harmless, but they waste space in long-lived module IR.
84 */
85void EliminateUnnecessaryBraces(Module& module);
86
87/**
88 * Eliminates functions in a program which are never called. Returns true if any changes were made.
89 */
90bool EliminateDeadFunctions(const Context& context, Module& module, ProgramUsage* usage);
91bool EliminateDeadFunctions(Program& program);
92
93/**
94 * Eliminates variables in a program which are never read or written (past their initializer).
95 * Preserves side effects from initializers, if any. Returns true if any changes were made.
96 */
97bool EliminateDeadLocalVariables(const Context& context,
98 Module& module,
99 ProgramUsage* usage);
100bool EliminateDeadLocalVariables(Program& program);
101bool EliminateDeadGlobalVariables(const Context& context,
102 Module& module,
103 ProgramUsage* usage,
104 bool onlyPrivateGlobals);
105bool EliminateDeadGlobalVariables(Program& program);
106
107/** Renames private functions and function-local variables to minimize code size. */
108void RenamePrivateSymbols(Context& context, Module& module, ProgramUsage* usage, ProgramKind kind);
109
110/** Replaces constant variables in a program with their equivalent values. */
111void ReplaceConstVarsWithLiterals(Module& module, ProgramUsage* usage);
112
113/**
114 * Looks for variables inside of the top-level of a switch body, such as:
115 *
116 * switch (x) {
117 * case 1: int i; // `i` is at top-level
118 * case 2: float f = 5.0; // `f` is at top-level, and has an initial-value assignment
119 * case 3: { bool b; } // `b` is not at top-level; it has an additional scope
120 * }
121 *
122 * If any top-level variables are found, a scoped block is created around the switch, and the
123 * variable declarations are moved out of the switch body and into the outer scope. (Variables with
124 * additional scoping are left as-is.) Then, we replace the declarations with assignment statements:
125 *
126 * {
127 * int i;
128 * float f;
129 * switch (a) {
130 * case 1: // `i` is declared above and does not need initialization
131 * case 2: f = 5.0; // `f` is declared above and initialized here
132 * case 3: { bool b; } // `b` is left as-is because it has a block-scope
133 * }
134 * }
135 *
136 * This doesn't change the meaning or correctness of the code. If the switch needs to be rewriten
137 * (e.g. due to the restrictions of ES2 or WGSL), this transformation prevents scoping issues with
138 * variables falling out of scope between switch-cases when we fall through.
139 *
140 * If there are no variables at the top-level, the switch statement is returned as-is.
141 */
142std::unique_ptr<Statement> HoistSwitchVarDeclarationsAtTopLevel(const Context&,
143 std::unique_ptr<SwitchStatement>);
144
145} // namespace Transform
146} // namespace SkSL
147
148#endif
ModifierFlags AddConstToVarModifiers(const Variable &var, const Expression *initialValue, const ProgramUsage *usage)
void ReplaceConstVarsWithLiterals(Module &module, ProgramUsage *usage)
bool EliminateDeadLocalVariables(const Context &context, Module &module, ProgramUsage *usage)
void EliminateUnreachableCode(Module &module, ProgramUsage *usage)
bool EliminateDeadFunctions(const Context &context, Module &module, ProgramUsage *usage)
std::unique_ptr< Expression > RewriteIndexedSwizzle(const Context &context, const IndexExpression &swizzle)
void FindAndDeclareBuiltinFunctions(Program &program)
void EliminateEmptyStatements(Module &module)
void EliminateUnnecessaryBraces(Module &module)
void FindAndDeclareBuiltinVariables(Program &program)
void FindAndDeclareBuiltinStructs(Program &program)
bool EliminateDeadGlobalVariables(const Context &context, Module &module, ProgramUsage *usage, bool onlyPrivateGlobals)
void RenamePrivateSymbols(Context &context, Module &module, ProgramUsage *usage, ProgramKind kind)
std::unique_ptr< Statement > HoistSwitchVarDeclarationsAtTopLevel(const Context &, std::unique_ptr< SwitchStatement >)
skgpu::graphite::Transform Transform
static void usage(char *argv0)