blob: b0a61e00a139084feef0bebf2ff222a1b9a17c90 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stilesb92641c2020-08-31 18:09:01 -040013#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/sksl/SkSLByteCodeGenerator.h"
15#include "src/sksl/SkSLCFGGenerator.h"
16#include "src/sksl/SkSLCPPCodeGenerator.h"
17#include "src/sksl/SkSLGLSLCodeGenerator.h"
18#include "src/sksl/SkSLHCodeGenerator.h"
19#include "src/sksl/SkSLIRGenerator.h"
20#include "src/sksl/SkSLMetalCodeGenerator.h"
21#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040022#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050024#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/ir/SkSLEnum.h"
26#include "src/sksl/ir/SkSLExpression.h"
27#include "src/sksl/ir/SkSLExpressionStatement.h"
28#include "src/sksl/ir/SkSLFunctionCall.h"
29#include "src/sksl/ir/SkSLIntLiteral.h"
30#include "src/sksl/ir/SkSLModifiersDeclaration.h"
31#include "src/sksl/ir/SkSLNop.h"
32#include "src/sksl/ir/SkSLSymbolTable.h"
33#include "src/sksl/ir/SkSLTernaryExpression.h"
34#include "src/sksl/ir/SkSLUnresolvedFunction.h"
35#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040036#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070037
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040038#include <fstream>
39
Ethan Nicholasa11035b2019-11-26 16:27:47 -050040#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
41#include "include/gpu/GrContextOptions.h"
42#include "src/gpu/GrShaderCaps.h"
43#endif
44
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040045#ifdef SK_ENABLE_SPIRV_VALIDATION
46#include "spirv-tools/libspirv.hpp"
47#endif
48
Brian Osman3d87e9f2020-10-08 11:50:22 -040049#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040050
Brian Osman3d87e9f2020-10-08 11:50:22 -040051// In standalone mode, we load the textual sksl source files. GN generates or copies these files
52// to the skslc executable directory. The "data" in this mode is just the filename.
53#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
54
55#else
56
57// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040058#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
59#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
60#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
61#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
62#include "src/sksl/generated/sksl_interp.dehydrated.sksl"
63#include "src/sksl/generated/sksl_pipeline.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050064#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040065#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
66
Brian Osman3d87e9f2020-10-08 11:50:22 -040067#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
68 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040069
70#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040071
ethannicholasb3058bd2016-07-01 08:22:01 -070072namespace SkSL {
73
Brian Osman88cda172020-10-09 12:05:16 -040074class AutoSource {
75public:
76 AutoSource(Compiler* compiler, const String* source)
77 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
78 fCompiler->fSource = source;
79 }
80
81 ~AutoSource() { fCompiler->fSource = fOldSource; }
82
83 Compiler* fCompiler;
84 const String* fOldSource;
85};
86
Brian Osmand7e76592020-11-02 12:26:22 -050087Compiler::Compiler(const ShaderCapsClass* caps, Flags flags)
Brian Osman0006ad02020-11-18 15:38:39 -050088 : fContext(std::make_shared<Context>())
89 , fCaps(caps)
90 , fInliner(fContext.get(), fCaps)
91 , fFlags(flags)
92 , fErrorCount(0) {
93 SkASSERT(fCaps);
John Stiles7c3515b2020-10-16 18:38:39 -040094 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050095 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stiles0f464502020-11-20 12:52:22 -050096 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), fCaps, *this);
ethannicholasb3058bd2016-07-01 08:22:01 -070097
Brian Osmanb06301e2020-11-06 11:45:36 -050098#define TYPE(t) fContext->f##t##_Type.get()
ethannicholasb3058bd2016-07-01 08:22:01 -070099
Brian Osmanb06301e2020-11-06 11:45:36 -0500100 const SkSL::Symbol* rootTypes[] = {
101 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500102
Brian Osmanb06301e2020-11-06 11:45:36 -0500103 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
104 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
105 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
106 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
107 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
108 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
109 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
110 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
111 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500112
Brian Osmanb06301e2020-11-06 11:45:36 -0500113 TYPE(Float2x2), TYPE(Float2x3), TYPE(Float2x4),
114 TYPE(Float3x2), TYPE(Float3x3), TYPE(Float3x4),
115 TYPE(Float4x2), TYPE(Float4x3), TYPE(Float4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500116
Brian Osmanb06301e2020-11-06 11:45:36 -0500117 TYPE(Half2x2), TYPE(Half2x3), TYPE(Half2x4),
118 TYPE(Half3x2), TYPE(Half3x3), TYPE(Half3x4),
119 TYPE(Half4x2), TYPE(Half4x3), TYPE(Half4x4),
ethannicholasb3058bd2016-07-01 08:22:01 -0700120
Brian Osmanb06301e2020-11-06 11:45:36 -0500121 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenUType), TYPE(GenBType),
122 TYPE(Mat), TYPE(Vec),
123 TYPE(GVec), TYPE(GVec2), TYPE(GVec3), TYPE(GVec4),
124 TYPE(HVec), TYPE(IVec), TYPE(UVec), TYPE(SVec), TYPE(USVec),
125 TYPE(ByteVec), TYPE(UByteVec), TYPE(BVec),
126
127 TYPE(FragmentProcessor),
128 };
129
130 const SkSL::Symbol* privateTypes[] = {
131 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
132 TYPE(SamplerExternalOES),
133 TYPE(SamplerCube),
134 TYPE(Sampler2DRect),
135 TYPE(Sampler1DArray), TYPE(Sampler2DArray), TYPE(SamplerCubeArray),
136 TYPE(SamplerBuffer),
137 TYPE(Sampler2DMS), TYPE(Sampler2DMSArray),
138
139 TYPE(ISampler2D),
140 TYPE(Image2D), TYPE(IImage2D),
141 TYPE(SubpassInput), TYPE(SubpassInputMS),
142
143 TYPE(GSampler1D), TYPE(GSampler2D), TYPE(GSampler3D),
144 TYPE(GSamplerCube),
145 TYPE(GSampler2DRect),
146 TYPE(GSampler1DArray), TYPE(GSampler2DArray), TYPE(GSamplerCubeArray),
147 TYPE(GSamplerBuffer),
148 TYPE(GSampler2DMS), TYPE(GSampler2DMSArray),
149
150 TYPE(Sampler1DShadow), TYPE(Sampler2DShadow), TYPE(SamplerCubeShadow),
151 TYPE(Sampler2DRectShadow),
152 TYPE(Sampler1DArrayShadow), TYPE(Sampler2DArrayShadow), TYPE(SamplerCubeArrayShadow),
153
154 TYPE(GSampler2DArrayShadow), TYPE(GSamplerCubeArrayShadow),
155 TYPE(Sampler),
156 TYPE(Texture2D),
157 };
158
159 for (const SkSL::Symbol* type : rootTypes) {
160 fRootSymbolTable->addWithoutOwnership(type);
161 }
162 for (const SkSL::Symbol* type : privateTypes) {
163 fPrivateSymbolTable->addWithoutOwnership(type);
164 }
165
166#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700167
Brian Osman3887a012020-09-30 13:22:27 -0400168 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
169 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500170 fPrivateSymbolTable->add(
171 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500172 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500173 "sk_Caps",
174 fContext->fSkCaps_Type.get(),
175 /*builtin=*/false,
176 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500177
Brian Osman3d87e9f2020-10-08 11:50:22 -0400178 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500179 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700180}
181
John Stilesdd13dba2020-10-29 10:45:34 -0400182Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700183
Brian Osman56269982020-11-20 12:38:07 -0500184const ParsedModule& Compiler::loadGPUModule() {
185 if (!fGPUModule.fSymbols) {
186 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
187 }
188 return fGPUModule;
189}
190
191const ParsedModule& Compiler::loadFragmentModule() {
192 if (!fFragmentModule.fSymbols) {
193 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag),
194 this->loadGPUModule());
195 }
196 return fFragmentModule;
197}
198
199const ParsedModule& Compiler::loadVertexModule() {
200 if (!fVertexModule.fSymbols) {
201 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert),
202 this->loadGPUModule());
203 }
204 return fVertexModule;
205}
206
Brian Osman88cda172020-10-09 12:05:16 -0400207const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400208 if (!fGeometryModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500209 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom),
210 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400211 }
Brian Osman88cda172020-10-09 12:05:16 -0400212 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400213}
214
Brian Osman88cda172020-10-09 12:05:16 -0400215const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400216 if (!fFPModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500217 fFPModule = this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp),
218 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400219 }
Brian Osman88cda172020-10-09 12:05:16 -0400220 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400221}
222
Brian Osmanb06301e2020-11-06 11:45:36 -0500223const ParsedModule& Compiler::loadPublicModule() {
224 if (!fPublicModule.fSymbols) {
225 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
226 }
227 return fPublicModule;
228}
229
Brian Osman88cda172020-10-09 12:05:16 -0400230const ParsedModule& Compiler::loadPipelineModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400231 if (!fPipelineModule.fSymbols) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500232 fPipelineModule = this->parseModule(Program::kPipelineStage_Kind, MODULE_DATA(pipeline),
233 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400234
235 // Add some aliases to the pipeline module so that it's friendlier, and more like GLSL
236 fPipelineModule.fSymbols->addAlias("shader", fContext->fFragmentProcessor_Type.get());
237
238 fPipelineModule.fSymbols->addAlias("vec2", fContext->fFloat2_Type.get());
239 fPipelineModule.fSymbols->addAlias("vec3", fContext->fFloat3_Type.get());
240 fPipelineModule.fSymbols->addAlias("vec4", fContext->fFloat4_Type.get());
241
242 fPipelineModule.fSymbols->addAlias("bvec2", fContext->fBool2_Type.get());
243 fPipelineModule.fSymbols->addAlias("bvec3", fContext->fBool3_Type.get());
244 fPipelineModule.fSymbols->addAlias("bvec4", fContext->fBool4_Type.get());
245
246 fPipelineModule.fSymbols->addAlias("mat2", fContext->fFloat2x2_Type.get());
247 fPipelineModule.fSymbols->addAlias("mat3", fContext->fFloat3x3_Type.get());
248 fPipelineModule.fSymbols->addAlias("mat4", fContext->fFloat4x4_Type.get());
249
250 fPipelineModule.fSymbols->addAlias("mat2x2", fContext->fFloat2x2_Type.get());
251 fPipelineModule.fSymbols->addAlias("mat2x3", fContext->fFloat2x3_Type.get());
252 fPipelineModule.fSymbols->addAlias("mat2x4", fContext->fFloat2x4_Type.get());
253
254 fPipelineModule.fSymbols->addAlias("mat3x2", fContext->fFloat3x2_Type.get());
255 fPipelineModule.fSymbols->addAlias("mat3x3", fContext->fFloat3x3_Type.get());
256 fPipelineModule.fSymbols->addAlias("mat3x4", fContext->fFloat3x4_Type.get());
257
258 fPipelineModule.fSymbols->addAlias("mat4x2", fContext->fFloat4x2_Type.get());
259 fPipelineModule.fSymbols->addAlias("mat4x3", fContext->fFloat4x3_Type.get());
260 fPipelineModule.fSymbols->addAlias("mat4x4", fContext->fFloat4x4_Type.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400261 }
Brian Osman88cda172020-10-09 12:05:16 -0400262 return fPipelineModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400263}
264
Brian Osman88cda172020-10-09 12:05:16 -0400265const ParsedModule& Compiler::loadInterpreterModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400266 if (!fInterpreterModule.fSymbols) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500267 fInterpreterModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(interp),
268 this->loadPublicModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400269 }
Brian Osman88cda172020-10-09 12:05:16 -0400270 return fInterpreterModule;
271}
272
273const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
274 switch (kind) {
Brian Osman56269982020-11-20 12:38:07 -0500275 case Program::kVertex_Kind: return this->loadVertexModule(); break;
276 case Program::kFragment_Kind: return this->loadFragmentModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400277 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
278 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
279 case Program::kPipelineStage_Kind: return this->loadPipelineModule(); break;
280 case Program::kGeneric_Kind: return this->loadInterpreterModule(); break;
281 }
282 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400283}
284
Brian Osman3d87e9f2020-10-08 11:50:22 -0400285LoadedModule Compiler::loadModule(Program::Kind kind,
286 ModuleData data,
287 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400288 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500289 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
290 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
291 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
292 // like samplers or textures. Today, 'Private' does contain the union of all known types,
293 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
294 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
295 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400296 }
297
298#if defined(SKSL_STANDALONE)
299 SkASSERT(data.fPath);
300 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400301 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
302 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400303 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400304 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400305 abort();
306 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400307 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400308 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400309 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400310 SkASSERT(fIRGenerator->fCanInline);
311 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400312 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500313 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500314 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500315 /*isBuiltinCode=*/true, source->c_str(), source->length(),
316 /*externalValues=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400317 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500318 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400319 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400320 if (this->fErrorCount) {
321 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400322 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400323 }
Brian Osman88cda172020-10-09 12:05:16 -0400324 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400325#else
326 SkASSERT(data.fData && (data.fSize != 0));
327 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
328 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500329 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400330 fModifiers.push_back(fIRGenerator->releaseModifiers());
331#endif
332
333 return module;
334}
335
336ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500337 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
338 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400339
340 // For modules that just declare (but don't define) intrinsic functions, there will be no new
341 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500342 if (module.fElements.empty()) {
343 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400344 }
345
346 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
347
348 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
349 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500350 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400351 switch (element->kind()) {
352 case ProgramElement::Kind::kFunction: {
353 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400354 SkASSERT(f.declaration().isBuiltin());
355 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400356 break;
357 }
John Stiles569249b2020-11-03 12:18:22 -0500358 case ProgramElement::Kind::kFunctionPrototype: {
359 // These are already in the symbol table.
360 break;
361 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400362 case ProgramElement::Kind::kEnum: {
363 const Enum& e = element->as<Enum>();
364 SkASSERT(e.isBuiltin());
365 intrinsics->insertOrDie(e.typeName(), std::move(element));
366 break;
367 }
368 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400369 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
370 const Variable& var = global.declaration()->as<VarDeclaration>().var();
371 SkASSERT(var.isBuiltin());
372 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400373 break;
374 }
375 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400376 const Variable& var = element->as<InterfaceBlock>().variable();
377 SkASSERT(var.isBuiltin());
378 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400379 break;
380 }
381 default:
382 printf("Unsupported element: %s\n", element->description().c_str());
383 SkASSERT(false);
384 break;
385 }
386 }
387
Brian Osman0006ad02020-11-18 15:38:39 -0500388 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400389}
390
ethannicholas22f939e2016-10-13 13:25:34 -0700391// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500392void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
393 DefinitionMap* definitions) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400394 switch (lvalue->kind()) {
395 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -0400396 const Variable& var = *lvalue->as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400397 if (var.storage() == Variable::Storage::kLocal) {
John Stiles796cdb72020-10-08 12:06:53 -0400398 definitions->set(&var, expr);
ethannicholas22f939e2016-10-13 13:25:34 -0700399 }
400 break;
401 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400402 case Expression::Kind::kSwizzle:
ethannicholas22f939e2016-10-13 13:25:34 -0700403 // We consider the variable written to as long as at least some of its components have
404 // been written to. This will lead to some false negatives (we won't catch it if you
405 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400406 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
407 // but since we pass foo as a whole it is flagged as an error) unless we perform a much
ethannicholas22f939e2016-10-13 13:25:34 -0700408 // more complicated whole-program analysis. This is probably good enough.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400409 this->addDefinition(lvalue->as<Swizzle>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400410 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700411 definitions);
412 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400413 case Expression::Kind::kIndex:
ethannicholas22f939e2016-10-13 13:25:34 -0700414 // see comments in Swizzle
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400415 this->addDefinition(lvalue->as<IndexExpression>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400416 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700417 definitions);
418 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400419 case Expression::Kind::kFieldAccess:
ethannicholas22f939e2016-10-13 13:25:34 -0700420 // see comments in Swizzle
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400421 this->addDefinition(lvalue->as<FieldAccess>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400422 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700423 definitions);
424 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400425 case Expression::Kind::kTernary:
Ethan Nicholasa583b812018-01-18 13:32:11 -0500426 // To simplify analysis, we just pretend that we write to both sides of the ternary.
427 // This allows for false positives (meaning we fail to detect that a variable might not
428 // have been assigned), but is preferable to false negatives.
Ethan Nicholasdd218162020-10-08 05:48:01 -0400429 this->addDefinition(lvalue->as<TernaryExpression>().ifTrue().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400430 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500431 definitions);
Ethan Nicholasdd218162020-10-08 05:48:01 -0400432 this->addDefinition(lvalue->as<TernaryExpression>().ifFalse().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400433 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500434 definitions);
435 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400436 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400437 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700438 default:
439 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400440 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700441 }
442}
443
444// add local variables defined by this node to the set
John Stiles796cdb72020-10-08 12:06:53 -0400445void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) {
John Stiles70025e52020-09-28 16:08:58 -0400446 if (node.isExpression()) {
447 Expression* expr = node.expression()->get();
448 switch (expr->kind()) {
449 case Expression::Kind::kBinary: {
450 BinaryExpression* b = &expr->as<BinaryExpression>();
451 if (b->getOperator() == Token::Kind::TK_EQ) {
John Stiles2d4f9592020-10-30 10:29:12 -0400452 this->addDefinition(b->left().get(), &b->right(), definitions);
John Stiles70025e52020-09-28 16:08:58 -0400453 } else if (Compiler::IsAssignment(b->getOperator())) {
454 this->addDefinition(
John Stiles2d4f9592020-10-30 10:29:12 -0400455 b->left().get(),
John Stiles70025e52020-09-28 16:08:58 -0400456 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
457 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500458
ethannicholas22f939e2016-10-13 13:25:34 -0700459 }
John Stiles70025e52020-09-28 16:08:58 -0400460 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700461 }
John Stiles70025e52020-09-28 16:08:58 -0400462 case Expression::Kind::kFunctionCall: {
463 const FunctionCall& c = expr->as<FunctionCall>();
Brian Osman5bf3e202020-10-13 10:34:18 -0400464 const std::vector<const Variable*>& parameters = c.function().parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400465 for (size_t i = 0; i < parameters.size(); ++i) {
466 if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stiles70025e52020-09-28 16:08:58 -0400467 this->addDefinition(
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400468 c.arguments()[i].get(),
John Stiles70025e52020-09-28 16:08:58 -0400469 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
470 definitions);
471 }
472 }
473 break;
474 }
475 case Expression::Kind::kPrefix: {
476 const PrefixExpression* p = &expr->as<PrefixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400477 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
478 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400479 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400480 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400481 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
482 definitions);
483 }
484 break;
485 }
486 case Expression::Kind::kPostfix: {
487 const PostfixExpression* p = &expr->as<PostfixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400488 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
489 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400490 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400491 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400492 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
493 definitions);
494 }
495 break;
496 }
497 case Expression::Kind::kVariableReference: {
498 const VariableReference* v = &expr->as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400499 if (v->refKind() != VariableReference::RefKind::kRead) {
John Stiles70025e52020-09-28 16:08:58 -0400500 this->addDefinition(
501 v,
502 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
503 definitions);
504 }
505 break;
506 }
507 default:
508 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700509 }
John Stiles70025e52020-09-28 16:08:58 -0400510 } else if (node.isStatement()) {
511 Statement* stmt = node.statement()->get();
512 if (stmt->is<VarDeclaration>()) {
513 VarDeclaration& vd = stmt->as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400514 if (vd.value()) {
515 definitions->set(&vd.var(), &vd.value());
ethannicholas22f939e2016-10-13 13:25:34 -0700516 }
ethannicholas22f939e2016-10-13 13:25:34 -0700517 }
518 }
519}
520
John Stilese6150002020-10-05 12:03:53 -0400521void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700522 BasicBlock& block = cfg->fBlocks[blockId];
523
524 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500525 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700526 for (const BasicBlock::Node& n : block.fNodes) {
527 this->addDefinitions(n, &after);
528 }
529
530 // propagate definitions to exits
531 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400532 if (exitId == blockId) {
533 continue;
534 }
ethannicholas22f939e2016-10-13 13:25:34 -0700535 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles796cdb72020-10-08 12:06:53 -0400536 after.foreach([&](const Variable* var, std::unique_ptr<Expression>** e1Ptr) {
537 std::unique_ptr<Expression>* e1 = *e1Ptr;
538 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
539 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400540 // exit has no definition for it, just copy it and reprocess exit block
541 processedSet->reset(exitId);
John Stiles796cdb72020-10-08 12:06:53 -0400542 exit.fBefore[var] = e1;
ethannicholas22f939e2016-10-13 13:25:34 -0700543 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500544 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400545 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700546 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400547 // definition has changed, merge and reprocess the exit block
548 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500549 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400550 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500551 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400552 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500553 }
ethannicholas22f939e2016-10-13 13:25:34 -0700554 }
555 }
John Stiles796cdb72020-10-08 12:06:53 -0400556 });
ethannicholas22f939e2016-10-13 13:25:34 -0700557 }
558}
559
560// returns a map which maps all local variables in the function to null, indicating that their value
561// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500562static DefinitionMap compute_start_state(const CFG& cfg) {
563 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400564 for (const auto& block : cfg.fBlocks) {
565 for (const auto& node : block.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -0400566 if (node.isStatement()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400567 const Statement* s = node.statement()->get();
Brian Osmanc0213602020-10-06 14:43:32 -0400568 if (s->is<VarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400569 result[&s->as<VarDeclaration>().var()] = nullptr;
ethannicholas22f939e2016-10-13 13:25:34 -0700570 }
571 }
572 }
573 }
574 return result;
575}
576
Ethan Nicholascb670962017-04-20 19:31:52 -0400577/**
578 * Returns true if assigning to this lvalue has no effect.
579 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400580static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400581 switch (lvalue.kind()) {
582 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400583 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400584 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400585 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400586 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400587 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400588 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400589 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400590 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400591 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400592 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400593 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400594 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400595 return !t.test()->hasSideEffects() &&
596 is_dead(*t.ifTrue(), usage) &&
597 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500598 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400599 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400600 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400601 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500602#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400603 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500604#endif
605 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400606 }
607}
ethannicholas22f939e2016-10-13 13:25:34 -0700608
Ethan Nicholascb670962017-04-20 19:31:52 -0400609/**
610 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
611 * to a dead target and lack of side effects on the left hand side.
612 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400613static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400614 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400615 return false;
616 }
John Stiles2d4f9592020-10-30 10:29:12 -0400617 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400618}
619
620void Compiler::computeDataFlow(CFG* cfg) {
621 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400622
623 // We set bits in the "processed" set after a block has been scanned.
624 SkBitSet processedSet(cfg->fBlocks.size());
625 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
626 processedSet.set(*blockId);
627 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700628 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400629}
630
631/**
632 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
633 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
634 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
635 * need to be regenerated).
636 */
John Stilesafbf8992020-08-18 10:08:21 -0400637static bool try_replace_expression(BasicBlock* b,
638 std::vector<BasicBlock::Node>::iterator* iter,
639 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400640 std::unique_ptr<Expression>* target = (*iter)->expression();
641 if (!b->tryRemoveExpression(iter)) {
642 *target = std::move(*newExpression);
643 return false;
644 }
645 *target = std::move(*newExpression);
646 return b->tryInsertExpression(iter, target);
647}
648
649/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400650 * Returns true if the expression is a constant numeric literal with the specified value, or a
651 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400652 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400653template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400654static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400655 switch (expr.kind()) {
656 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400657 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400658
Ethan Nicholase6592142020-09-08 10:22:09 -0400659 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400660 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400661
Ethan Nicholase6592142020-09-08 10:22:09 -0400662 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400663 const Constructor& constructor = expr.as<Constructor>();
664 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400665 const Type& constructorType = constructor.type();
666 bool isFloat = constructorType.columns() > 1
667 ? constructorType.componentType().isFloat()
668 : constructorType.isFloat();
669 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400670 case Type::TypeKind::kVector:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400671 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400672 if (isFloat) {
673 if (constructor.getFVecComponent(i) != value) {
674 return false;
675 }
676 } else {
677 if (constructor.getIVecComponent(i) != value) {
678 return false;
679 }
680 }
Ethan Nicholasd188c182019-06-10 15:55:38 -0400681 }
John Stiles9d944232020-08-19 09:56:49 -0400682 return true;
683
Ethan Nicholase6592142020-09-08 10:22:09 -0400684 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400685 SkASSERT(constructor.arguments().size() == 1);
686 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400687
688 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400689 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400690 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400691 }
692 return false;
693 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400694 default:
695 return false;
696 }
697}
698
699/**
700 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
701 * and CFG structures).
702 */
John Stilesafbf8992020-08-18 10:08:21 -0400703static void delete_left(BasicBlock* b,
704 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400705 Compiler::OptimizationContext* optimizationContext) {
706 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400707 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400708 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400709 Expression& left = *bin.left();
710 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400711 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400712 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400713 if (bin.getOperator() == Token::Kind::TK_EQ) {
714 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400715 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400716 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400717 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400718 // Remove references within LHS.
719 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400720 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400721 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400722 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400723 return;
724 }
725 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400726 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400727 return;
728 }
729 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400730 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400731 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400732 return;
733 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400734 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400735 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400736}
737
738/**
739 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
740 * CFG structures).
741 */
John Stilesafbf8992020-08-18 10:08:21 -0400742static void delete_right(BasicBlock* b,
743 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400744 Compiler::OptimizationContext* optimizationContext) {
745 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400746 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400747 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400748 std::unique_ptr<Expression>& leftPointer = bin.left();
749 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400750 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400751 // Remove references within RHS.
752 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400753 if (!b->tryRemoveExpressionBefore(iter, &right)) {
754 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400755 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400756 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400757 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400758 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400759 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400760 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400761 return;
762 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400763 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400764 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400765 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400766 return;
767 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400768 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400769 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400770}
771
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400772/**
773 * Constructs the specified type using a single argument.
774 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400775static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400776 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400777 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400778 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400779 return result;
780}
781
782/**
783 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
784 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
785 */
786static void vectorize(BasicBlock* b,
787 std::vector<BasicBlock::Node>::iterator* iter,
788 const Type& type,
789 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400790 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400791 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
792 SkASSERT(type.typeKind() == Type::TypeKind::kVector);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400793 SkASSERT((*otherExpression)->type().typeKind() == Type::TypeKind::kScalar);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400794 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400795 std::unique_ptr<Expression>* target = (*iter)->expression();
796 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400797 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400798 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400799 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400800 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400801 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400802 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400803 }
804 }
805}
806
807/**
808 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
809 * left to yield vec<n>(x).
810 */
811static void vectorize_left(BasicBlock* b,
812 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400813 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400814 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400815 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400816 optimizationContext->fUsage->remove(bin.right().get());
817 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400818}
819
820/**
821 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
822 * right to yield vec<n>(y).
823 */
824static void vectorize_right(BasicBlock* b,
825 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400826 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400827 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400828 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400829 optimizationContext->fUsage->remove(bin.left().get());
830 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400831}
832
833// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400834static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400835 switch (expr.kind()) {
836 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400837 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400838 break;
839 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400840 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400841 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400842 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400843 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400844 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400845 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400846 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400847 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400848 break;
849 default:
850 ABORT("shouldn't be writing to this kind of expression\n");
851 break;
852 }
853}
854
Ethan Nicholascb670962017-04-20 19:31:52 -0400855void Compiler::simplifyExpression(DefinitionMap& definitions,
856 BasicBlock& b,
857 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400858 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400859 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400860 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500861
Ethan Nicholascb670962017-04-20 19:31:52 -0400862 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400863 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
864 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400865 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400866 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400867 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400868 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400869 // Remove references within 'expr', add references within 'optimized'
870 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400871 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400872 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400873 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400874 }
John Stiles70025e52020-09-28 16:08:58 -0400875 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400876 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400877 }
878 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400879 switch (expr->kind()) {
880 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400881 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400882 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400883 if (ref.refKind() != VariableReference::RefKind::kWrite &&
884 ref.refKind() != VariableReference::RefKind::kPointer &&
885 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400886 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
887 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000888 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400889 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400890 }
891 break;
892 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400893 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400894 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400895 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400896 // ternary has a constant test, replace it with either the true or
897 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400898 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400899 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400900 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400901 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400902 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400903 optimizationContext->fUpdated = true;
904 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400905 }
906 break;
907 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400908 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400909 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400910 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400911 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400912 break;
913 }
John Stiles2d4f9592020-10-30 10:29:12 -0400914 Expression& left = *bin->left();
915 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400916 const Type& leftType = left.type();
917 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400918 // collapse useless expressions like x * 1 or x + 0
Ethan Nicholas30d30222020-09-11 12:27:26 -0400919 if (((leftType.typeKind() != Type::TypeKind::kScalar) &&
920 (leftType.typeKind() != Type::TypeKind::kVector)) ||
921 ((rightType.typeKind() != Type::TypeKind::kScalar) &&
922 (rightType.typeKind() != Type::TypeKind::kVector))) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400923 break;
924 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400925 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400926 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400927 if (is_constant(left, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400928 if (leftType.typeKind() == Type::TypeKind::kVector &&
929 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400930 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400931 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400932 } else {
933 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400934 // 1 * float4(x) -> float4(x)
935 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400936 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400937 }
938 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400939 else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400940 if (leftType.typeKind() == Type::TypeKind::kScalar &&
941 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400942 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400943 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400944 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400945 } else {
946 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400947 // float4(0) * x -> float4(0)
948 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400949 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400950 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500951 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400952 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400953 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400954 else if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400955 if (leftType.typeKind() == Type::TypeKind::kScalar &&
956 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400957 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400958 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400959 } else {
960 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400961 // float4(x) * 1 -> float4(x)
962 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400963 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400964 }
965 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400966 else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400967 if (leftType.typeKind() == Type::TypeKind::kVector &&
968 rightType.typeKind() == Type::TypeKind::kScalar &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400969 !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400970 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400971 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400972 } else {
973 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400974 // x * float4(0) -> float4(0)
975 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400976 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400977 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500978 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400979 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400980 }
981 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400982 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400983 if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400984 if (leftType.typeKind() == Type::TypeKind::kVector &&
985 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400986 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400987 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400988 } else {
989 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400990 // 0 + float4(x) -> float4(x)
991 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400992 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400993 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400994 } else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400995 if (leftType.typeKind() == Type::TypeKind::kScalar &&
996 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400997 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400998 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400999 } else {
1000 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001001 // float4(x) + 0 -> float4(x)
1002 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001003 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001004 }
Ethan Nicholas56e42712017-04-21 10:23:37 -04001005 }
1006 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001007 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001008 if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001009 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1010 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001011 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001012 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001013 } else {
1014 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001015 // float4(x) - 0 -> float4(x)
1016 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001017 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001018 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001019 }
1020 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001021 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001022 if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001023 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1024 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001025 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001026 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001027 } else {
1028 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001029 // float4(x) / 1 -> float4(x)
1030 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001031 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001032 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001033 } else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001034 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1035 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001036 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001037 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001038 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001039 } else {
1040 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001041 // float4(0) / x -> float4(0)
1042 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001043 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001044 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001045 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001046 }
1047 }
1048 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001049 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001050 if (is_constant(right, 0)) {
1051 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001052 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001053 }
1054 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001055 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001056 if (is_constant(right, 0)) {
1057 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001058 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001059 }
1060 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001061 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001062 if (is_constant(right, 1)) {
1063 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001064 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001065 }
1066 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001067 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001068 if (is_constant(right, 1)) {
1069 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001070 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001071 }
1072 break;
1073 default:
1074 break;
1075 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001076 break;
1077 }
John Stilesf5c1d042020-11-21 23:26:07 -05001078 case Expression::Kind::kConstructor: {
1079 // Find constructors embedded inside constructors and flatten them out where possible.
1080 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
1081 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
1082 // Leave single-argument constructors alone, though. These might be casts or splats.
1083 Constructor& c = expr->as<Constructor>();
1084 if (c.type().columns() > 1) {
1085 // Inspect each constructor argument to see if it's a candidate for flattening.
1086 // Remember matched arguments in a bitfield, "argsToOptimize".
1087 int argsToOptimize = 0;
1088 int currBit = 1;
1089 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1090 if (arg->is<Constructor>()) {
1091 Constructor& inner = arg->as<Constructor>();
1092 if (inner.arguments().size() > 1 &&
1093 inner.type().componentType() == c.type().componentType()) {
1094 argsToOptimize |= currBit;
1095 }
1096 }
1097 currBit <<= 1;
1098 }
1099 if (argsToOptimize) {
1100 // We found at least one argument that could be flattened out. Re-walk the
1101 // constructor args and flatten the candidates we found during our initial pass.
1102 ExpressionArray flattened;
1103 flattened.reserve_back(c.type().columns());
1104 currBit = 1;
1105 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1106 if (argsToOptimize & currBit) {
1107 Constructor& inner = arg->as<Constructor>();
1108 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
1109 flattened.push_back(innerArg->clone());
1110 }
1111 } else {
1112 flattened.push_back(arg->clone());
1113 }
1114 currBit <<= 1;
1115 }
1116 auto optimized = std::unique_ptr<Expression>(
1117 new Constructor(c.fOffset, &c.type(), std::move(flattened)));
1118 // No fUsage change; no references have been added or removed anywhere.
1119 optimizationContext->fUpdated = true;
1120 if (!try_replace_expression(&b, iter, &optimized)) {
1121 optimizationContext->fNeedsRescan = true;
1122 return;
1123 }
1124 SkASSERT((*iter)->isExpression());
1125 break;
1126 }
1127 }
1128 break;
1129 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001130 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001131 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -05001132 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001133 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001134 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001135 for (int i = 0; i < (int) s.components().size(); ++i) {
1136 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001137 identity = false;
1138 break;
1139 }
1140 }
1141 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001142 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001143 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001144 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001145 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001146 return;
1147 }
John Stiles70025e52020-09-28 16:08:58 -04001148 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001149 break;
1150 }
1151 }
John Stiles108bbe22020-11-18 11:10:38 -05001152 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1153 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001154 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001155 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001156 for (int c : s.components()) {
1157 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001158 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001159 optimizationContext->fUpdated = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001160 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001161 final));
John Stiles108bbe22020-11-18 11:10:38 -05001162 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001163 if (!try_replace_expression(&b, iter, &replacement)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001164 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001165 return;
1166 }
John Stiles70025e52020-09-28 16:08:58 -04001167 SkASSERT((*iter)->isExpression());
John Stiles108bbe22020-11-18 11:10:38 -05001168 break;
1169 }
1170 // Optimize swizzles of constructors.
1171 if (s.base()->is<Constructor>()) {
1172 Constructor& base = s.base()->as<Constructor>();
1173 std::unique_ptr<Expression> replacement;
1174 const Type& componentType = base.type().componentType();
1175 int swizzleSize = s.components().size();
1176
1177 // The IR generator has already converted any zero/one swizzle components into
1178 // constructors containing zero/one args. Confirm that this is true by checking that
1179 // our swizzle components are all `xyzw` (values 0 through 3).
1180 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1181 [](int8_t c) { return c >= 0 && c <= 3; }));
1182
1183 if (base.arguments().size() == 1 &&
1184 base.arguments().front()->type().typeKind() == Type::TypeKind::kScalar) {
1185 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1186 // components don't actually matter since all fields are the same.
1187 ExpressionArray newArgs;
1188 newArgs.push_back(base.arguments().front()->clone());
1189 replacement = std::make_unique<Constructor>(
1190 base.fOffset,
1191 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1192 std::move(newArgs));
1193
1194 // No fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent reference
1195 // counts.
John Stiles0777ac42020-11-19 11:06:47 -05001196 optimizationContext->fUpdated = true;
John Stiles108bbe22020-11-18 11:10:38 -05001197 if (!try_replace_expression(&b, iter, &replacement)) {
1198 optimizationContext->fNeedsRescan = true;
1199 return;
1200 }
1201 SkASSERT((*iter)->isExpression());
1202 break;
1203 }
1204
John Stiles0777ac42020-11-19 11:06:47 -05001205 // Swizzles can duplicate some elements and discard others, e.g.
1206 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1207 // - Expressions with side effects need to occur exactly once, even if they
1208 // would otherwise be swizzle-eliminated
1209 // - Non-trivial expressions should not be repeated, but elimination is OK.
1210 //
1211 // Look up the argument for the constructor at each index. This is typically simple
1212 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1213 // seems. This example would result in:
1214 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1215 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1216 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1217 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1218 struct ConstructorArgMap {
1219 int8_t fArgIndex;
1220 int8_t fComponent;
1221 };
1222
1223 int numConstructorArgs = base.type().columns();
1224 ConstructorArgMap argMap[4] = {};
1225 int writeIdx = 0;
1226 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1227 const Expression& expr = *base.arguments()[argIdx];
1228 int argWidth = expr.type().columns();
1229 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1230 argMap[writeIdx].fArgIndex = argIdx;
1231 argMap[writeIdx].fComponent = componentIdx;
1232 ++writeIdx;
1233 }
1234 }
1235 SkASSERT(writeIdx == numConstructorArgs);
1236
1237 // Count up the number of times each constructor argument is used by the
1238 // swizzle.
1239 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1240 // - bar.yz is referenced 3 times, by `.x_xy`
1241 // - half(foo) is referenced 1 time, by `._w__`
1242 int8_t exprUsed[4] = {};
1243 for (int c : s.components()) {
1244 exprUsed[argMap[c].fArgIndex]++;
1245 }
1246
1247 bool safeToOptimize = true;
1248 for (int index = 0; index < numConstructorArgs; ++index) {
1249 int8_t constructorArgIndex = argMap[index].fArgIndex;
1250 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1251
1252 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001253 if (exprUsed[constructorArgIndex] > 1 &&
1254 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001255 safeToOptimize = false;
1256 break;
1257 }
1258 // Check that side-effect-bearing expressions are swizzled in exactly once.
1259 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1260 safeToOptimize = false;
1261 break;
1262 }
1263 }
1264
1265 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001266 struct ReorderedArgument {
1267 int8_t fArgIndex;
1268 ComponentArray fComponents;
1269 };
1270 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001271 for (int c : s.components()) {
1272 const ConstructorArgMap& argument = argMap[c];
1273 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1274
1275 if (baseArg.type().typeKind() == Type::TypeKind::kScalar) {
John Stilesd9076cb2020-11-19 12:18:36 -05001276 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001277 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001278 reorderedArgs.push_back({argument.fArgIndex,
1279 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001280 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001281 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001282 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001283 if (reorderedArgs.empty() ||
1284 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1285 // This can't be combined with the previous argument. Add a new one.
1286 reorderedArgs.push_back({argument.fArgIndex,
1287 ComponentArray{argument.fComponent}});
1288 } else {
1289 // Since we know this argument uses components, it should already
1290 // have at least one component set.
1291 SkASSERT(!reorderedArgs.back().fComponents.empty());
1292 // Build up the current argument with one more component.
1293 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1294 }
John Stiles0777ac42020-11-19 11:06:47 -05001295 }
1296 }
John Stilesd9076cb2020-11-19 12:18:36 -05001297
1298 // Convert our reordered argument list to an actual array of expressions, with
1299 // the new order and any new inner swizzles that need to be applied. Note that
1300 // we expect followup passes to clean up the inner swizzles.
1301 ExpressionArray newArgs;
1302 newArgs.reserve_back(swizzleSize);
1303 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1304 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1305 if (reorderedArg.fComponents.empty()) {
1306 newArgs.push_back(baseArg.clone());
1307 } else {
1308 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1309 reorderedArg.fComponents));
1310 }
1311 }
1312
1313 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001314 replacement = std::make_unique<Constructor>(
1315 base.fOffset,
1316 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1317 std::move(newArgs));
1318
1319 // Remove references within 'expr', add references within 'optimized'
1320 optimizationContext->fUpdated = true;
1321 optimizationContext->fUsage->replace(expr, replacement.get());
1322 if (!try_replace_expression(&b, iter, &replacement)) {
1323 optimizationContext->fNeedsRescan = true;
1324 return;
1325 }
1326 SkASSERT((*iter)->isExpression());
1327 }
John Stiles108bbe22020-11-18 11:10:38 -05001328 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001329 }
John Stiles30212b72020-06-11 17:55:07 -04001330 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001331 }
1332 default:
1333 break;
1334 }
1335}
1336
John Stiles92219b42020-06-15 12:32:24 -04001337// Returns true if this statement could potentially execute a break at the current level. We ignore
1338// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001339static bool contains_conditional_break(Statement& stmt) {
1340 class ContainsConditionalBreak : public ProgramVisitor {
1341 public:
1342 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001343 switch (stmt.kind()) {
1344 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001345 return this->INHERITED::visitStatement(stmt);
1346
Ethan Nicholase6592142020-09-08 10:22:09 -04001347 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001348 return fInConditional > 0;
1349
Ethan Nicholase6592142020-09-08 10:22:09 -04001350 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001351 ++fInConditional;
1352 bool result = this->INHERITED::visitStatement(stmt);
1353 --fInConditional;
1354 return result;
1355 }
1356
1357 default:
1358 return false;
1359 }
1360 }
1361
1362 int fInConditional = 0;
1363 using INHERITED = ProgramVisitor;
1364 };
1365
1366 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001367}
1368
Ethan Nicholas5005a222018-08-24 13:06:27 -04001369// returns true if this statement definitely executes a break at the current level (we ignore
1370// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001371static bool contains_unconditional_break(Statement& stmt) {
1372 class ContainsUnconditionalBreak : public ProgramVisitor {
1373 public:
1374 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001375 switch (stmt.kind()) {
1376 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001377 return this->INHERITED::visitStatement(stmt);
1378
Ethan Nicholase6592142020-09-08 10:22:09 -04001379 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001380 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001381
1382 default:
1383 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001384 }
John Stilesb92641c2020-08-31 18:09:01 -04001385 }
John Stiles92219b42020-06-15 12:32:24 -04001386
John Stilesb92641c2020-08-31 18:09:01 -04001387 using INHERITED = ProgramVisitor;
1388 };
John Stiles92219b42020-06-15 12:32:24 -04001389
John Stilesb92641c2020-08-31 18:09:01 -04001390 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001391}
1392
John Stiles8f2a0cf2020-10-13 12:48:21 -04001393static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001394 switch (stmt->kind()) {
1395 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001396 // Recurse into the block.
1397 Block& block = static_cast<Block&>(*stmt);
1398
John Stiles8f2a0cf2020-10-13 12:48:21 -04001399 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001400 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001401 for (std::unique_ptr<Statement>& stmt : block.children()) {
1402 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001403 }
John Stiles92219b42020-06-15 12:32:24 -04001404
1405 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001406 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001407 break;
John Stiles92219b42020-06-15 12:32:24 -04001408 }
1409
Ethan Nicholase6592142020-09-08 10:22:09 -04001410 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001411 // Do not append a break to the target.
1412 break;
1413
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001414 default:
John Stiles92219b42020-06-15 12:32:24 -04001415 // Append normal statements to the target.
1416 target->push_back(std::move(stmt));
1417 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001418 }
1419}
1420
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001421// Returns a block containing all of the statements that will be run if the given case matches
1422// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1423// broken by this call and must then be discarded).
1424// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1425// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001426static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1427 SwitchCase* caseToCapture) {
1428 // We have to be careful to not move any of the pointers until after we're sure we're going to
1429 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1430 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001431 auto iter = switchStatement->cases().begin();
1432 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001433 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001434 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001435 }
John Stiles92219b42020-06-15 12:32:24 -04001436 }
1437
1438 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1439 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1440 // statements that we can use for simplification.
1441 auto startIter = iter;
1442 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001443 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001444 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001445 if (contains_conditional_break(*stmt)) {
1446 // We can't reduce switch-cases to a block when they have conditional breaks.
1447 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001448 }
John Stiles92219b42020-06-15 12:32:24 -04001449
1450 if (contains_unconditional_break(*stmt)) {
1451 // We found an unconditional break. We can use this block, but we need to strip
1452 // out the break statement.
1453 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001454 break;
1455 }
1456 }
John Stiles92219b42020-06-15 12:32:24 -04001457
1458 if (unconditionalBreakStmt != nullptr) {
1459 break;
1460 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001461 }
John Stiles92219b42020-06-15 12:32:24 -04001462
1463 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1464 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001465 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001466
1467 // We can move over most of the statements as-is.
1468 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001469 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001470 caseStmts.push_back(std::move(stmt));
1471 }
1472 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001473 }
John Stiles92219b42020-06-15 12:32:24 -04001474
1475 // If we found an unconditional break at the end, we need to move what we can while avoiding
1476 // that break.
1477 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001478 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001479 if (stmt.get() == unconditionalBreakStmt) {
1480 move_all_but_break(stmt, &caseStmts);
1481 unconditionalBreakStmt = nullptr;
1482 break;
1483 }
1484
1485 caseStmts.push_back(std::move(stmt));
1486 }
1487 }
1488
1489 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1490
1491 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001492 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001493}
1494
Ethan Nicholascb670962017-04-20 19:31:52 -04001495void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001496 BasicBlock& b,
1497 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001498 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001499 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001500 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001501 switch (stmt->kind()) {
1502 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001503 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001504 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001505 (!varDecl.value() ||
1506 !varDecl.value()->hasSideEffects())) {
1507 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001508 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001509 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001510 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001511 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001512 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001513 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001514 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001515 }
1516 break;
1517 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001518 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001519 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001520 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001521 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001522 if (i.test()->as<BoolLiteral>().value()) {
1523 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001524 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001525 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001526 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001527 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001528 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001529 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001530 }
1531 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001532 optimizationContext->fUpdated = true;
1533 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001534 break;
1535 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001536 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001537 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001538 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001539 optimizationContext->fUpdated = true;
1540 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001541 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001542 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001543 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001544 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001545 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001546 (*iter)->setStatement(
1547 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001548 } else {
1549 // no if, no else, no test side effects, kill the whole if
1550 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001551 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001552 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001553 optimizationContext->fUpdated = true;
1554 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001555 }
1556 break;
1557 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001558 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001559 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001560 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001561 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001562 // switch is constant, replace it with the case that matches
1563 bool found = false;
1564 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001565 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1566 if (!c->value()) {
1567 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001568 continue;
1569 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001570 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001571 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001572 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001573 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001574 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001575 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001576 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001577 break;
1578 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001579 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1580 optimizationContext->fSilences.find(&s) ==
1581 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001582 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001583 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001584 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001585 }
1586 return; // can't simplify
1587 }
1588 }
1589 }
1590 if (!found) {
1591 // no matching case. use default if it exists, or kill the whole thing
1592 if (defaultCase) {
1593 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1594 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001595 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001596 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001597 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1598 optimizationContext->fSilences.find(&s) ==
1599 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001600 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001601 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001602 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001603 }
1604 return; // can't simplify
1605 }
1606 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001607 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001608 }
1609 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001610 optimizationContext->fUpdated = true;
1611 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001612 }
1613 break;
1614 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001615 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001616 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001617 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001618 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001619 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001620 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001621 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001622 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001623 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001624 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001625 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001626 }
1627 break;
1628 }
1629 default:
1630 break;
1631 }
1632}
1633
Brian Osman010ce6a2020-10-19 16:34:10 -04001634bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001635 bool madeChanges = false;
1636
Ethan Nicholascb670962017-04-20 19:31:52 -04001637 CFG cfg = CFGGenerator().getCFG(f);
1638 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001639
1640 // check for unreachable code
1641 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001642 const BasicBlock& block = cfg.fBlocks[i];
John Stiles61e75e32020-10-01 15:42:37 -04001643 if (i != cfg.fStart && !block.fIsReachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001644 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001645 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001646 if (node.isStatement()) {
1647 offset = (*node.statement())->fOffset;
1648 } else {
1649 offset = (*node.expression())->fOffset;
1650 if ((*node.expression())->is<BoolLiteral>()) {
1651 // Function inlining can generate do { ... } while(false) loops which always
1652 // break, so the boolean condition is considered unreachable. Since not being
1653 // able to reach a literal is a non-issue in the first place, we don't report an
1654 // error in this case.
1655 continue;
1656 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001657 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001658 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001659 }
1660 }
1661 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001662 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001663 }
1664
Ethan Nicholascb670962017-04-20 19:31:52 -04001665 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001666 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001667 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001668 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001669 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001670 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001671 cfg = CFGGenerator().getCFG(f);
1672 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001673 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001674 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001675
John Stiles7d3f0892020-11-03 11:35:01 -05001676 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001677 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001678
1679 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1680 if (eliminatedBlockIds.test(blockId)) {
1681 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1682 optimizationContext.fUpdated = true;
1683 optimizationContext.fNeedsRescan = true;
1684 break;
1685 }
1686
1687 BasicBlock& b = cfg.fBlocks[blockId];
1688 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001689 // Block was reachable before optimization, but has since become unreachable. In
1690 // addition to being dead code, it's broken - since control flow can't reach it, no
1691 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001692 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001693 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001694 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001695 // Eliminating a node runs the risk of eliminating that node's exits as
1696 // well. Keep track of this and do a rescan if we are about to access one
1697 // of these.
1698 for (BlockId id : b.fExits) {
1699 eliminatedBlockIds.set(id);
1700 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001701 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001702 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001703 }
1704 }
1705 continue;
1706 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001707 DefinitionMap definitions = b.fBefore;
1708
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001709 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1710 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001711 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001712 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001713 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001714 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001715 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001716 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001717 break;
1718 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001719 this->addDefinitions(*iter, &definitions);
1720 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001721
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001722 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001723 break;
1724 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001725 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001726 madeChanges |= optimizationContext.fUpdated;
1727 } while (optimizationContext.fUpdated);
1728 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001729
Ethan Nicholas91a10532017-06-22 11:24:38 -04001730 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001731 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001732 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1733 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001734 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001735 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001736 switch (s.kind()) {
1737 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001738 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001739 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001740 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001741 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001742 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001743 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001744 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001745 if (s.as<SwitchStatement>().isStatic() &&
1746 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1747 optimizationContext.fSilences.find(&s) ==
1748 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001749 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001750 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001751 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001752 break;
1753 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001754 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001755 break;
1756 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001757 } else {
1758 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001759 }
1760 }
1761 }
1762
ethannicholas22f939e2016-10-13 13:25:34 -07001763 // check for missing return
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001764 if (f.declaration().returnType() != *fContext->fVoid_Type) {
John Stiles61e75e32020-10-01 15:42:37 -04001765 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001766 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001767 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001768 }
1769 }
John Stiles0cc193a2020-09-09 09:39:34 -04001770
1771 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001772}
1773
Brian Osman32d53552020-09-23 13:55:20 -04001774std::unique_ptr<Program> Compiler::convertProgram(
1775 Program::Kind kind,
1776 String text,
1777 const Program::Settings& settings,
1778 const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
1779 SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001780
Brian Osman0006ad02020-11-18 15:38:39 -05001781 // Loading and optimizing our base module might reset the inliner, so do that first,
1782 // *then* configure the inliner with the settings for this program.
1783 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1784
ethannicholasb3058bd2016-07-01 08:22:01 -07001785 fErrorText = "";
1786 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001787 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001788
1789 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001790 std::unique_ptr<String> textPtr(new String(std::move(text)));
1791 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001792
John Stiles5c7bb322020-10-22 11:09:15 -04001793 // Enable node pooling while converting and optimizing the program for a performance boost.
1794 // The Program will take ownership of the pool.
John Stiles2d68ea32020-10-22 15:42:27 -04001795 std::unique_ptr<Pool> pool = Pool::Create();
1796 pool->attachToThread();
Brian Osman0006ad02020-11-18 15:38:39 -05001797 IRGenerator::IRBundle ir =
1798 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
1799 textPtr->c_str(), textPtr->size(), externalValues);
John Stiles5c7bb322020-10-22 11:09:15 -04001800 auto program = std::make_unique<Program>(kind,
1801 std::move(textPtr),
1802 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001803 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001804 fContext,
1805 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001806 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001807 std::move(ir.fModifiers),
1808 std::move(ir.fSymbolTable),
1809 std::move(pool),
1810 ir.fInputs);
1811 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001812 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001813 // Do not return programs that failed to compile.
1814 } else if (settings.fOptimize && !this->optimize(*program)) {
1815 // Do not return programs that failed to optimize.
1816 } else {
1817 // We have a successful program!
1818 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001819 }
John Stiles5c7bb322020-10-22 11:09:15 -04001820
1821 program->fPool->detachFromThread();
1822 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001823}
1824
Brian Osman0006ad02020-11-18 15:38:39 -05001825bool Compiler::optimize(LoadedModule& module) {
1826 SkASSERT(!fErrorCount);
1827 Program::Settings settings;
1828 fIRGenerator->fKind = module.fKind;
1829 fIRGenerator->fSettings = &settings;
1830 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1831
1832 fInliner.reset(fModifiers.back().get(), &settings);
1833
1834 while (fErrorCount == 0) {
1835 bool madeChanges = false;
1836
1837 // Scan and optimize based on the control-flow graph for each function.
1838 for (const auto& element : module.fElements) {
1839 if (element->is<FunctionDefinition>()) {
1840 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1841 }
1842 }
1843
1844 // Perform inline-candidate analysis and inline any functions deemed suitable.
1845 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols.get(), usage.get());
1846
1847 if (!madeChanges) {
1848 break;
1849 }
1850 }
1851 return fErrorCount == 0;
1852}
1853
Ethan Nicholas00543112018-07-31 09:44:36 -04001854bool Compiler::optimize(Program& program) {
1855 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001856 fIRGenerator->fKind = program.fKind;
1857 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001858 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001859
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001860 while (fErrorCount == 0) {
1861 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001862
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001863 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001864 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001865 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001866 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001867 }
1868 }
1869
1870 // Perform inline-candidate analysis and inline any functions deemed suitable.
Brian Osman0006ad02020-11-18 15:38:39 -05001871 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols.get(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001872
1873 // Remove dead functions. We wait until after analysis so that we still report errors,
1874 // even in unused code.
1875 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001876 auto isDeadFunction = [&](const ProgramElement* element) {
1877 if (!element->is<FunctionDefinition>()) {
1878 return false;
1879 }
1880 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1881 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1882 usage->remove(*element);
1883 madeChanges = true;
1884 return true;
1885 }
1886 return false;
1887 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001888 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001889 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001890 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001891 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001892 }),
1893 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001894 program.fSharedElements.erase(
1895 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1896 isDeadFunction),
1897 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001898 }
1899
1900 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001901 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001902 auto isDeadVariable = [&](const ProgramElement* element) {
1903 if (!element->is<GlobalVarDeclaration>()) {
1904 return false;
1905 }
1906 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1907 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1908 if (usage->isDead(varDecl.var())) {
1909 madeChanges = true;
1910 return true;
1911 }
1912 return false;
1913 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001914 program.fElements.erase(
1915 std::remove_if(program.fElements.begin(), program.fElements.end(),
1916 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001917 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001918 }),
1919 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001920 program.fSharedElements.erase(
1921 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1922 isDeadVariable),
1923 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001924 }
John Stiles73a6bff2020-09-09 13:40:37 -04001925
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001926 if (!madeChanges) {
1927 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001928 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001929 }
1930 return fErrorCount == 0;
1931}
1932
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001933#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1934
Ethan Nicholas00543112018-07-31 09:44:36 -04001935bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001936#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001937 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001938 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001939 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001940 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001941 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001942 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001943 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001944 SkASSERT(0 == data.size() % 4);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001945 auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
1946 SkDebugf("SPIR-V validation error: %s\n", m);
1947 };
1948 tools.SetMessageConsumer(dumpmsg);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001949 // Verify that the SPIR-V we produced is valid. If this SkASSERT fails, check the logs prior
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001950 // to the failure to see the validation errors.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001951 SkAssertResult(tools.Validate((const uint32_t*) data.c_str(), data.size() / 4));
Ethan Nicholas762466e2017-06-29 10:03:38 -04001952 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001953 }
1954#else
Brian Osman88cda172020-10-09 12:05:16 -04001955 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001956 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001957 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001958#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001959 return result;
1960}
1961
Ethan Nicholas00543112018-07-31 09:44:36 -04001962bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001963 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001964 bool result = this->toSPIRV(program, buffer);
1965 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001966 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001967 }
1968 return result;
1969}
1970
Ethan Nicholas00543112018-07-31 09:44:36 -04001971bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001972 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001973 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001974 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001975 return result;
1976}
1977
Ethan Nicholas00543112018-07-31 09:44:36 -04001978bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001979 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001980 bool result = this->toGLSL(program, buffer);
1981 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001982 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001983 }
1984 return result;
1985}
1986
Brian Osmanc0243912020-02-19 15:35:26 -05001987bool Compiler::toHLSL(Program& program, String* out) {
1988 String spirv;
1989 if (!this->toSPIRV(program, &spirv)) {
1990 return false;
1991 }
1992
1993 return SPIRVtoHLSL(spirv, out);
1994}
1995
Ethan Nicholas00543112018-07-31 09:44:36 -04001996bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001997 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001998 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001999 return result;
2000}
2001
Ethan Nicholas00543112018-07-31 09:44:36 -04002002bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04002003 StringStream buffer;
2004 bool result = this->toMetal(program, buffer);
2005 if (result) {
2006 *out = buffer.str();
2007 }
2008 return result;
2009}
2010
Greg Daniela28ea672020-09-25 11:12:56 -04002011#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002012bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002013 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002014 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002015 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04002016 return result;
2017}
2018
Ethan Nicholas00543112018-07-31 09:44:36 -04002019bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002020 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002021 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002022 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002023 return result;
2024}
Greg Daniela28ea672020-09-25 11:12:56 -04002025#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002026
Ethan Nicholas2a479a52020-08-18 16:29:45 -04002027#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04002028
2029#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04002030bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04002031 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04002032 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05002033 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04002034 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002035 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05002036 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04002037 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04002038 return result;
2039}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04002040#endif
2041
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002042std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Brian Osman88cda172020-10-09 12:05:16 -04002043 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002044 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04002045 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
2046 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04002047 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002048 return result;
2049 }
2050 return nullptr;
2051}
2052
Brian Osman401a0092020-09-10 14:47:24 -04002053const char* Compiler::OperatorName(Token::Kind op) {
2054 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002055 case Token::Kind::TK_PLUS: return "+";
2056 case Token::Kind::TK_MINUS: return "-";
2057 case Token::Kind::TK_STAR: return "*";
2058 case Token::Kind::TK_SLASH: return "/";
2059 case Token::Kind::TK_PERCENT: return "%";
2060 case Token::Kind::TK_SHL: return "<<";
2061 case Token::Kind::TK_SHR: return ">>";
2062 case Token::Kind::TK_LOGICALNOT: return "!";
2063 case Token::Kind::TK_LOGICALAND: return "&&";
2064 case Token::Kind::TK_LOGICALOR: return "||";
2065 case Token::Kind::TK_LOGICALXOR: return "^^";
2066 case Token::Kind::TK_BITWISENOT: return "~";
2067 case Token::Kind::TK_BITWISEAND: return "&";
2068 case Token::Kind::TK_BITWISEOR: return "|";
2069 case Token::Kind::TK_BITWISEXOR: return "^";
2070 case Token::Kind::TK_EQ: return "=";
2071 case Token::Kind::TK_EQEQ: return "==";
2072 case Token::Kind::TK_NEQ: return "!=";
2073 case Token::Kind::TK_LT: return "<";
2074 case Token::Kind::TK_GT: return ">";
2075 case Token::Kind::TK_LTEQ: return "<=";
2076 case Token::Kind::TK_GTEQ: return ">=";
2077 case Token::Kind::TK_PLUSEQ: return "+=";
2078 case Token::Kind::TK_MINUSEQ: return "-=";
2079 case Token::Kind::TK_STAREQ: return "*=";
2080 case Token::Kind::TK_SLASHEQ: return "/=";
2081 case Token::Kind::TK_PERCENTEQ: return "%=";
2082 case Token::Kind::TK_SHLEQ: return "<<=";
2083 case Token::Kind::TK_SHREQ: return ">>=";
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002084 case Token::Kind::TK_BITWISEANDEQ: return "&=";
2085 case Token::Kind::TK_BITWISEOREQ: return "|=";
2086 case Token::Kind::TK_BITWISEXOREQ: return "^=";
2087 case Token::Kind::TK_PLUSPLUS: return "++";
2088 case Token::Kind::TK_MINUSMINUS: return "--";
2089 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002090 default:
Brian Osman401a0092020-09-10 14:47:24 -04002091 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002092 }
2093}
2094
2095
2096bool Compiler::IsAssignment(Token::Kind op) {
2097 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002098 case Token::Kind::TK_EQ: // fall through
2099 case Token::Kind::TK_PLUSEQ: // fall through
2100 case Token::Kind::TK_MINUSEQ: // fall through
2101 case Token::Kind::TK_STAREQ: // fall through
2102 case Token::Kind::TK_SLASHEQ: // fall through
2103 case Token::Kind::TK_PERCENTEQ: // fall through
2104 case Token::Kind::TK_SHLEQ: // fall through
2105 case Token::Kind::TK_SHREQ: // fall through
2106 case Token::Kind::TK_BITWISEOREQ: // fall through
2107 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05002108 case Token::Kind::TK_BITWISEANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002109 return true;
2110 default:
2111 return false;
2112 }
2113}
2114
Brian Osman401a0092020-09-10 14:47:24 -04002115Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
2116 switch (op) {
2117 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
2118 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
2119 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
2120 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
2121 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
2122 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
2123 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
2124 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
2125 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
2126 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
Brian Osman401a0092020-09-10 14:47:24 -04002127 default: return op;
2128 }
2129}
2130
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002131Position Compiler::position(int offset) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002132 SkASSERT(fSource);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002133 int line = 1;
2134 int column = 1;
2135 for (int i = 0; i < offset; i++) {
2136 if ((*fSource)[i] == '\n') {
2137 ++line;
2138 column = 1;
2139 }
2140 else {
2141 ++column;
2142 }
2143 }
2144 return Position(line, column);
2145}
2146
2147void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002148 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002149 Position pos = this->position(offset);
2150 fErrorText += "error: " + to_string(pos.fLine) + ": " + msg.c_str() + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07002151}
2152
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002153String Compiler::errorText() {
Ethan Nicholas00543112018-07-31 09:44:36 -04002154 this->writeErrorCount();
2155 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002156 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07002157 return result;
2158}
2159
2160void Compiler::writeErrorCount() {
2161 if (fErrorCount) {
2162 fErrorText += to_string(fErrorCount) + " error";
2163 if (fErrorCount > 1) {
2164 fErrorText += "s";
2165 }
2166 fErrorText += "\n";
2167 }
2168}
2169
John Stilesa6841be2020-08-06 14:11:56 -04002170} // namespace SkSL