blob: fd87d9b1c0b647640e02a8cab18ac32b72330dcf [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 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001078 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001079 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -05001080 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001081 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001082 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001083 for (int i = 0; i < (int) s.components().size(); ++i) {
1084 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001085 identity = false;
1086 break;
1087 }
1088 }
1089 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001090 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001091 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001092 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001093 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001094 return;
1095 }
John Stiles70025e52020-09-28 16:08:58 -04001096 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001097 break;
1098 }
1099 }
John Stiles108bbe22020-11-18 11:10:38 -05001100 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1101 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001102 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001103 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001104 for (int c : s.components()) {
1105 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001106 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001107 optimizationContext->fUpdated = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001108 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001109 final));
John Stiles108bbe22020-11-18 11:10:38 -05001110 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001111 if (!try_replace_expression(&b, iter, &replacement)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001112 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001113 return;
1114 }
John Stiles70025e52020-09-28 16:08:58 -04001115 SkASSERT((*iter)->isExpression());
John Stiles108bbe22020-11-18 11:10:38 -05001116 break;
1117 }
1118 // Optimize swizzles of constructors.
1119 if (s.base()->is<Constructor>()) {
1120 Constructor& base = s.base()->as<Constructor>();
1121 std::unique_ptr<Expression> replacement;
1122 const Type& componentType = base.type().componentType();
1123 int swizzleSize = s.components().size();
1124
1125 // The IR generator has already converted any zero/one swizzle components into
1126 // constructors containing zero/one args. Confirm that this is true by checking that
1127 // our swizzle components are all `xyzw` (values 0 through 3).
1128 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1129 [](int8_t c) { return c >= 0 && c <= 3; }));
1130
1131 if (base.arguments().size() == 1 &&
1132 base.arguments().front()->type().typeKind() == Type::TypeKind::kScalar) {
1133 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1134 // components don't actually matter since all fields are the same.
1135 ExpressionArray newArgs;
1136 newArgs.push_back(base.arguments().front()->clone());
1137 replacement = std::make_unique<Constructor>(
1138 base.fOffset,
1139 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1140 std::move(newArgs));
1141
1142 // No fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent reference
1143 // counts.
John Stiles0777ac42020-11-19 11:06:47 -05001144 optimizationContext->fUpdated = true;
John Stiles108bbe22020-11-18 11:10:38 -05001145 if (!try_replace_expression(&b, iter, &replacement)) {
1146 optimizationContext->fNeedsRescan = true;
1147 return;
1148 }
1149 SkASSERT((*iter)->isExpression());
1150 break;
1151 }
1152
John Stiles0777ac42020-11-19 11:06:47 -05001153 // Swizzles can duplicate some elements and discard others, e.g.
1154 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1155 // - Expressions with side effects need to occur exactly once, even if they
1156 // would otherwise be swizzle-eliminated
1157 // - Non-trivial expressions should not be repeated, but elimination is OK.
1158 //
1159 // Look up the argument for the constructor at each index. This is typically simple
1160 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1161 // seems. This example would result in:
1162 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1163 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1164 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1165 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1166 struct ConstructorArgMap {
1167 int8_t fArgIndex;
1168 int8_t fComponent;
1169 };
1170
1171 int numConstructorArgs = base.type().columns();
1172 ConstructorArgMap argMap[4] = {};
1173 int writeIdx = 0;
1174 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1175 const Expression& expr = *base.arguments()[argIdx];
1176 int argWidth = expr.type().columns();
1177 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1178 argMap[writeIdx].fArgIndex = argIdx;
1179 argMap[writeIdx].fComponent = componentIdx;
1180 ++writeIdx;
1181 }
1182 }
1183 SkASSERT(writeIdx == numConstructorArgs);
1184
1185 // Count up the number of times each constructor argument is used by the
1186 // swizzle.
1187 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1188 // - bar.yz is referenced 3 times, by `.x_xy`
1189 // - half(foo) is referenced 1 time, by `._w__`
1190 int8_t exprUsed[4] = {};
1191 for (int c : s.components()) {
1192 exprUsed[argMap[c].fArgIndex]++;
1193 }
1194
1195 bool safeToOptimize = true;
1196 for (int index = 0; index < numConstructorArgs; ++index) {
1197 int8_t constructorArgIndex = argMap[index].fArgIndex;
1198 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1199
1200 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001201 if (exprUsed[constructorArgIndex] > 1 &&
1202 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001203 safeToOptimize = false;
1204 break;
1205 }
1206 // Check that side-effect-bearing expressions are swizzled in exactly once.
1207 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1208 safeToOptimize = false;
1209 break;
1210 }
1211 }
1212
1213 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001214 struct ReorderedArgument {
1215 int8_t fArgIndex;
1216 ComponentArray fComponents;
1217 };
1218 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001219 for (int c : s.components()) {
1220 const ConstructorArgMap& argument = argMap[c];
1221 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1222
1223 if (baseArg.type().typeKind() == Type::TypeKind::kScalar) {
John Stilesd9076cb2020-11-19 12:18:36 -05001224 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001225 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001226 reorderedArgs.push_back({argument.fArgIndex,
1227 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001228 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001229 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001230 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001231 if (reorderedArgs.empty() ||
1232 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1233 // This can't be combined with the previous argument. Add a new one.
1234 reorderedArgs.push_back({argument.fArgIndex,
1235 ComponentArray{argument.fComponent}});
1236 } else {
1237 // Since we know this argument uses components, it should already
1238 // have at least one component set.
1239 SkASSERT(!reorderedArgs.back().fComponents.empty());
1240 // Build up the current argument with one more component.
1241 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1242 }
John Stiles0777ac42020-11-19 11:06:47 -05001243 }
1244 }
John Stilesd9076cb2020-11-19 12:18:36 -05001245
1246 // Convert our reordered argument list to an actual array of expressions, with
1247 // the new order and any new inner swizzles that need to be applied. Note that
1248 // we expect followup passes to clean up the inner swizzles.
1249 ExpressionArray newArgs;
1250 newArgs.reserve_back(swizzleSize);
1251 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1252 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1253 if (reorderedArg.fComponents.empty()) {
1254 newArgs.push_back(baseArg.clone());
1255 } else {
1256 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1257 reorderedArg.fComponents));
1258 }
1259 }
1260
1261 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001262 replacement = std::make_unique<Constructor>(
1263 base.fOffset,
1264 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1265 std::move(newArgs));
1266
1267 // Remove references within 'expr', add references within 'optimized'
1268 optimizationContext->fUpdated = true;
1269 optimizationContext->fUsage->replace(expr, replacement.get());
1270 if (!try_replace_expression(&b, iter, &replacement)) {
1271 optimizationContext->fNeedsRescan = true;
1272 return;
1273 }
1274 SkASSERT((*iter)->isExpression());
1275 }
John Stiles108bbe22020-11-18 11:10:38 -05001276 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001277 }
John Stiles30212b72020-06-11 17:55:07 -04001278 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001279 }
1280 default:
1281 break;
1282 }
1283}
1284
John Stiles92219b42020-06-15 12:32:24 -04001285// Returns true if this statement could potentially execute a break at the current level. We ignore
1286// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001287static bool contains_conditional_break(Statement& stmt) {
1288 class ContainsConditionalBreak : public ProgramVisitor {
1289 public:
1290 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001291 switch (stmt.kind()) {
1292 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001293 return this->INHERITED::visitStatement(stmt);
1294
Ethan Nicholase6592142020-09-08 10:22:09 -04001295 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001296 return fInConditional > 0;
1297
Ethan Nicholase6592142020-09-08 10:22:09 -04001298 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001299 ++fInConditional;
1300 bool result = this->INHERITED::visitStatement(stmt);
1301 --fInConditional;
1302 return result;
1303 }
1304
1305 default:
1306 return false;
1307 }
1308 }
1309
1310 int fInConditional = 0;
1311 using INHERITED = ProgramVisitor;
1312 };
1313
1314 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001315}
1316
Ethan Nicholas5005a222018-08-24 13:06:27 -04001317// returns true if this statement definitely executes a break at the current level (we ignore
1318// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001319static bool contains_unconditional_break(Statement& stmt) {
1320 class ContainsUnconditionalBreak : public ProgramVisitor {
1321 public:
1322 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001323 switch (stmt.kind()) {
1324 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001325 return this->INHERITED::visitStatement(stmt);
1326
Ethan Nicholase6592142020-09-08 10:22:09 -04001327 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001328 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001329
1330 default:
1331 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001332 }
John Stilesb92641c2020-08-31 18:09:01 -04001333 }
John Stiles92219b42020-06-15 12:32:24 -04001334
John Stilesb92641c2020-08-31 18:09:01 -04001335 using INHERITED = ProgramVisitor;
1336 };
John Stiles92219b42020-06-15 12:32:24 -04001337
John Stilesb92641c2020-08-31 18:09:01 -04001338 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001339}
1340
John Stiles8f2a0cf2020-10-13 12:48:21 -04001341static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001342 switch (stmt->kind()) {
1343 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001344 // Recurse into the block.
1345 Block& block = static_cast<Block&>(*stmt);
1346
John Stiles8f2a0cf2020-10-13 12:48:21 -04001347 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001348 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001349 for (std::unique_ptr<Statement>& stmt : block.children()) {
1350 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001351 }
John Stiles92219b42020-06-15 12:32:24 -04001352
1353 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001354 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001355 break;
John Stiles92219b42020-06-15 12:32:24 -04001356 }
1357
Ethan Nicholase6592142020-09-08 10:22:09 -04001358 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001359 // Do not append a break to the target.
1360 break;
1361
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001362 default:
John Stiles92219b42020-06-15 12:32:24 -04001363 // Append normal statements to the target.
1364 target->push_back(std::move(stmt));
1365 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001366 }
1367}
1368
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001369// Returns a block containing all of the statements that will be run if the given case matches
1370// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1371// broken by this call and must then be discarded).
1372// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1373// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001374static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1375 SwitchCase* caseToCapture) {
1376 // We have to be careful to not move any of the pointers until after we're sure we're going to
1377 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1378 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001379 auto iter = switchStatement->cases().begin();
1380 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001381 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001382 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001383 }
John Stiles92219b42020-06-15 12:32:24 -04001384 }
1385
1386 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1387 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1388 // statements that we can use for simplification.
1389 auto startIter = iter;
1390 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001391 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001392 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001393 if (contains_conditional_break(*stmt)) {
1394 // We can't reduce switch-cases to a block when they have conditional breaks.
1395 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001396 }
John Stiles92219b42020-06-15 12:32:24 -04001397
1398 if (contains_unconditional_break(*stmt)) {
1399 // We found an unconditional break. We can use this block, but we need to strip
1400 // out the break statement.
1401 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001402 break;
1403 }
1404 }
John Stiles92219b42020-06-15 12:32:24 -04001405
1406 if (unconditionalBreakStmt != nullptr) {
1407 break;
1408 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001409 }
John Stiles92219b42020-06-15 12:32:24 -04001410
1411 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1412 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001413 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001414
1415 // We can move over most of the statements as-is.
1416 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001417 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001418 caseStmts.push_back(std::move(stmt));
1419 }
1420 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001421 }
John Stiles92219b42020-06-15 12:32:24 -04001422
1423 // If we found an unconditional break at the end, we need to move what we can while avoiding
1424 // that break.
1425 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001426 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001427 if (stmt.get() == unconditionalBreakStmt) {
1428 move_all_but_break(stmt, &caseStmts);
1429 unconditionalBreakStmt = nullptr;
1430 break;
1431 }
1432
1433 caseStmts.push_back(std::move(stmt));
1434 }
1435 }
1436
1437 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1438
1439 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001440 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001441}
1442
Ethan Nicholascb670962017-04-20 19:31:52 -04001443void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001444 BasicBlock& b,
1445 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001446 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001447 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001448 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001449 switch (stmt->kind()) {
1450 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001451 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001452 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001453 (!varDecl.value() ||
1454 !varDecl.value()->hasSideEffects())) {
1455 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001456 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001457 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001458 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001459 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001460 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001461 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001462 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001463 }
1464 break;
1465 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001466 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001467 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001468 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001469 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001470 if (i.test()->as<BoolLiteral>().value()) {
1471 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001472 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001473 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001474 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001475 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001476 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001477 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001478 }
1479 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001480 optimizationContext->fUpdated = true;
1481 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001482 break;
1483 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001484 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001485 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001486 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001487 optimizationContext->fUpdated = true;
1488 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001489 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001490 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001491 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001492 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001493 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001494 (*iter)->setStatement(
1495 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001496 } else {
1497 // no if, no else, no test side effects, kill the whole if
1498 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001499 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001500 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001501 optimizationContext->fUpdated = true;
1502 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001503 }
1504 break;
1505 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001506 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001507 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001508 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001509 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001510 // switch is constant, replace it with the case that matches
1511 bool found = false;
1512 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001513 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1514 if (!c->value()) {
1515 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001516 continue;
1517 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001518 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001519 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001520 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001521 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001522 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001523 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001524 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001525 break;
1526 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001527 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1528 optimizationContext->fSilences.find(&s) ==
1529 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001530 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001531 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001532 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001533 }
1534 return; // can't simplify
1535 }
1536 }
1537 }
1538 if (!found) {
1539 // no matching case. use default if it exists, or kill the whole thing
1540 if (defaultCase) {
1541 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1542 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001543 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001544 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001545 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1546 optimizationContext->fSilences.find(&s) ==
1547 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001548 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001549 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001550 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001551 }
1552 return; // can't simplify
1553 }
1554 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001555 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001556 }
1557 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001558 optimizationContext->fUpdated = true;
1559 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001560 }
1561 break;
1562 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001563 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001564 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001565 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001566 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001567 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001568 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001569 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001570 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001571 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001572 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001573 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001574 }
1575 break;
1576 }
1577 default:
1578 break;
1579 }
1580}
1581
Brian Osman010ce6a2020-10-19 16:34:10 -04001582bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001583 bool madeChanges = false;
1584
Ethan Nicholascb670962017-04-20 19:31:52 -04001585 CFG cfg = CFGGenerator().getCFG(f);
1586 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001587
1588 // check for unreachable code
1589 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001590 const BasicBlock& block = cfg.fBlocks[i];
John Stiles61e75e32020-10-01 15:42:37 -04001591 if (i != cfg.fStart && !block.fIsReachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001592 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001593 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001594 if (node.isStatement()) {
1595 offset = (*node.statement())->fOffset;
1596 } else {
1597 offset = (*node.expression())->fOffset;
1598 if ((*node.expression())->is<BoolLiteral>()) {
1599 // Function inlining can generate do { ... } while(false) loops which always
1600 // break, so the boolean condition is considered unreachable. Since not being
1601 // able to reach a literal is a non-issue in the first place, we don't report an
1602 // error in this case.
1603 continue;
1604 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001605 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001606 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001607 }
1608 }
1609 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001610 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001611 }
1612
Ethan Nicholascb670962017-04-20 19:31:52 -04001613 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001614 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001615 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001616 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001617 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001618 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001619 cfg = CFGGenerator().getCFG(f);
1620 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001621 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001622 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001623
John Stiles7d3f0892020-11-03 11:35:01 -05001624 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001625 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001626
1627 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1628 if (eliminatedBlockIds.test(blockId)) {
1629 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1630 optimizationContext.fUpdated = true;
1631 optimizationContext.fNeedsRescan = true;
1632 break;
1633 }
1634
1635 BasicBlock& b = cfg.fBlocks[blockId];
1636 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001637 // Block was reachable before optimization, but has since become unreachable. In
1638 // addition to being dead code, it's broken - since control flow can't reach it, no
1639 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001640 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001641 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001642 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001643 // Eliminating a node runs the risk of eliminating that node's exits as
1644 // well. Keep track of this and do a rescan if we are about to access one
1645 // of these.
1646 for (BlockId id : b.fExits) {
1647 eliminatedBlockIds.set(id);
1648 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001649 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001650 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001651 }
1652 }
1653 continue;
1654 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001655 DefinitionMap definitions = b.fBefore;
1656
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001657 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1658 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001659 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001660 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001661 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001662 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001663 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001664 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001665 break;
1666 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001667 this->addDefinitions(*iter, &definitions);
1668 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001669
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001670 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001671 break;
1672 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001673 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001674 madeChanges |= optimizationContext.fUpdated;
1675 } while (optimizationContext.fUpdated);
1676 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001677
Ethan Nicholas91a10532017-06-22 11:24:38 -04001678 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001679 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001680 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1681 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001682 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001683 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001684 switch (s.kind()) {
1685 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001686 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001687 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001688 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001689 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001690 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001691 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001692 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001693 if (s.as<SwitchStatement>().isStatic() &&
1694 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1695 optimizationContext.fSilences.find(&s) ==
1696 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001697 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001698 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001699 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001700 break;
1701 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001702 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001703 break;
1704 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001705 } else {
1706 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001707 }
1708 }
1709 }
1710
ethannicholas22f939e2016-10-13 13:25:34 -07001711 // check for missing return
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001712 if (f.declaration().returnType() != *fContext->fVoid_Type) {
John Stiles61e75e32020-10-01 15:42:37 -04001713 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001714 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001715 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001716 }
1717 }
John Stiles0cc193a2020-09-09 09:39:34 -04001718
1719 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001720}
1721
Brian Osman32d53552020-09-23 13:55:20 -04001722std::unique_ptr<Program> Compiler::convertProgram(
1723 Program::Kind kind,
1724 String text,
1725 const Program::Settings& settings,
1726 const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
1727 SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001728
Brian Osman0006ad02020-11-18 15:38:39 -05001729 // Loading and optimizing our base module might reset the inliner, so do that first,
1730 // *then* configure the inliner with the settings for this program.
1731 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1732
ethannicholasb3058bd2016-07-01 08:22:01 -07001733 fErrorText = "";
1734 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001735 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001736
1737 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001738 std::unique_ptr<String> textPtr(new String(std::move(text)));
1739 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001740
John Stiles5c7bb322020-10-22 11:09:15 -04001741 // Enable node pooling while converting and optimizing the program for a performance boost.
1742 // The Program will take ownership of the pool.
John Stiles2d68ea32020-10-22 15:42:27 -04001743 std::unique_ptr<Pool> pool = Pool::Create();
1744 pool->attachToThread();
Brian Osman0006ad02020-11-18 15:38:39 -05001745 IRGenerator::IRBundle ir =
1746 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
1747 textPtr->c_str(), textPtr->size(), externalValues);
John Stiles5c7bb322020-10-22 11:09:15 -04001748 auto program = std::make_unique<Program>(kind,
1749 std::move(textPtr),
1750 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001751 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001752 fContext,
1753 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001754 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001755 std::move(ir.fModifiers),
1756 std::move(ir.fSymbolTable),
1757 std::move(pool),
1758 ir.fInputs);
1759 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001760 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001761 // Do not return programs that failed to compile.
1762 } else if (settings.fOptimize && !this->optimize(*program)) {
1763 // Do not return programs that failed to optimize.
1764 } else {
1765 // We have a successful program!
1766 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001767 }
John Stiles5c7bb322020-10-22 11:09:15 -04001768
1769 program->fPool->detachFromThread();
1770 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001771}
1772
Brian Osman0006ad02020-11-18 15:38:39 -05001773bool Compiler::optimize(LoadedModule& module) {
1774 SkASSERT(!fErrorCount);
1775 Program::Settings settings;
1776 fIRGenerator->fKind = module.fKind;
1777 fIRGenerator->fSettings = &settings;
1778 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1779
1780 fInliner.reset(fModifiers.back().get(), &settings);
1781
1782 while (fErrorCount == 0) {
1783 bool madeChanges = false;
1784
1785 // Scan and optimize based on the control-flow graph for each function.
1786 for (const auto& element : module.fElements) {
1787 if (element->is<FunctionDefinition>()) {
1788 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1789 }
1790 }
1791
1792 // Perform inline-candidate analysis and inline any functions deemed suitable.
1793 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols.get(), usage.get());
1794
1795 if (!madeChanges) {
1796 break;
1797 }
1798 }
1799 return fErrorCount == 0;
1800}
1801
Ethan Nicholas00543112018-07-31 09:44:36 -04001802bool Compiler::optimize(Program& program) {
1803 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001804 fIRGenerator->fKind = program.fKind;
1805 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001806 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001807
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001808 while (fErrorCount == 0) {
1809 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001810
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001811 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001812 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001813 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001814 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001815 }
1816 }
1817
1818 // Perform inline-candidate analysis and inline any functions deemed suitable.
Brian Osman0006ad02020-11-18 15:38:39 -05001819 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols.get(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001820
1821 // Remove dead functions. We wait until after analysis so that we still report errors,
1822 // even in unused code.
1823 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001824 auto isDeadFunction = [&](const ProgramElement* element) {
1825 if (!element->is<FunctionDefinition>()) {
1826 return false;
1827 }
1828 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1829 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1830 usage->remove(*element);
1831 madeChanges = true;
1832 return true;
1833 }
1834 return false;
1835 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001836 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001837 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001838 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001839 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001840 }),
1841 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001842 program.fSharedElements.erase(
1843 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1844 isDeadFunction),
1845 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001846 }
1847
1848 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001849 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001850 auto isDeadVariable = [&](const ProgramElement* element) {
1851 if (!element->is<GlobalVarDeclaration>()) {
1852 return false;
1853 }
1854 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1855 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1856 if (usage->isDead(varDecl.var())) {
1857 madeChanges = true;
1858 return true;
1859 }
1860 return false;
1861 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001862 program.fElements.erase(
1863 std::remove_if(program.fElements.begin(), program.fElements.end(),
1864 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001865 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001866 }),
1867 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001868 program.fSharedElements.erase(
1869 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1870 isDeadVariable),
1871 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001872 }
John Stiles73a6bff2020-09-09 13:40:37 -04001873
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001874 if (!madeChanges) {
1875 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001876 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001877 }
1878 return fErrorCount == 0;
1879}
1880
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001881#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1882
Ethan Nicholas00543112018-07-31 09:44:36 -04001883bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001884#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001885 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001886 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001887 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001888 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001889 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001890 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001891 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001892 SkASSERT(0 == data.size() % 4);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001893 auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
1894 SkDebugf("SPIR-V validation error: %s\n", m);
1895 };
1896 tools.SetMessageConsumer(dumpmsg);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001897 // Verify that the SPIR-V we produced is valid. If this SkASSERT fails, check the logs prior
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001898 // to the failure to see the validation errors.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001899 SkAssertResult(tools.Validate((const uint32_t*) data.c_str(), data.size() / 4));
Ethan Nicholas762466e2017-06-29 10:03:38 -04001900 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001901 }
1902#else
Brian Osman88cda172020-10-09 12:05:16 -04001903 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001904 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001905 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001906#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001907 return result;
1908}
1909
Ethan Nicholas00543112018-07-31 09:44:36 -04001910bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001911 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001912 bool result = this->toSPIRV(program, buffer);
1913 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001914 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001915 }
1916 return result;
1917}
1918
Ethan Nicholas00543112018-07-31 09:44:36 -04001919bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001920 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001921 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001922 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001923 return result;
1924}
1925
Ethan Nicholas00543112018-07-31 09:44:36 -04001926bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001927 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001928 bool result = this->toGLSL(program, buffer);
1929 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001930 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001931 }
1932 return result;
1933}
1934
Brian Osmanc0243912020-02-19 15:35:26 -05001935bool Compiler::toHLSL(Program& program, String* out) {
1936 String spirv;
1937 if (!this->toSPIRV(program, &spirv)) {
1938 return false;
1939 }
1940
1941 return SPIRVtoHLSL(spirv, out);
1942}
1943
Ethan Nicholas00543112018-07-31 09:44:36 -04001944bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001945 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001946 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001947 return result;
1948}
1949
Ethan Nicholas00543112018-07-31 09:44:36 -04001950bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001951 StringStream buffer;
1952 bool result = this->toMetal(program, buffer);
1953 if (result) {
1954 *out = buffer.str();
1955 }
1956 return result;
1957}
1958
Greg Daniela28ea672020-09-25 11:12:56 -04001959#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001960bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001961 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001962 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001963 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001964 return result;
1965}
1966
Ethan Nicholas00543112018-07-31 09:44:36 -04001967bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001968 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001969 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001970 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001971 return result;
1972}
Greg Daniela28ea672020-09-25 11:12:56 -04001973#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001974
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001975#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001976
1977#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04001978bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04001979 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04001980 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05001981 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04001982 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001983 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05001984 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04001985 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001986 return result;
1987}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001988#endif
1989
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001990std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Brian Osman88cda172020-10-09 12:05:16 -04001991 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001992 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04001993 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
1994 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04001995 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001996 return result;
1997 }
1998 return nullptr;
1999}
2000
Brian Osman401a0092020-09-10 14:47:24 -04002001const char* Compiler::OperatorName(Token::Kind op) {
2002 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002003 case Token::Kind::TK_PLUS: return "+";
2004 case Token::Kind::TK_MINUS: return "-";
2005 case Token::Kind::TK_STAR: return "*";
2006 case Token::Kind::TK_SLASH: return "/";
2007 case Token::Kind::TK_PERCENT: return "%";
2008 case Token::Kind::TK_SHL: return "<<";
2009 case Token::Kind::TK_SHR: return ">>";
2010 case Token::Kind::TK_LOGICALNOT: return "!";
2011 case Token::Kind::TK_LOGICALAND: return "&&";
2012 case Token::Kind::TK_LOGICALOR: return "||";
2013 case Token::Kind::TK_LOGICALXOR: return "^^";
2014 case Token::Kind::TK_BITWISENOT: return "~";
2015 case Token::Kind::TK_BITWISEAND: return "&";
2016 case Token::Kind::TK_BITWISEOR: return "|";
2017 case Token::Kind::TK_BITWISEXOR: return "^";
2018 case Token::Kind::TK_EQ: return "=";
2019 case Token::Kind::TK_EQEQ: return "==";
2020 case Token::Kind::TK_NEQ: return "!=";
2021 case Token::Kind::TK_LT: return "<";
2022 case Token::Kind::TK_GT: return ">";
2023 case Token::Kind::TK_LTEQ: return "<=";
2024 case Token::Kind::TK_GTEQ: return ">=";
2025 case Token::Kind::TK_PLUSEQ: return "+=";
2026 case Token::Kind::TK_MINUSEQ: return "-=";
2027 case Token::Kind::TK_STAREQ: return "*=";
2028 case Token::Kind::TK_SLASHEQ: return "/=";
2029 case Token::Kind::TK_PERCENTEQ: return "%=";
2030 case Token::Kind::TK_SHLEQ: return "<<=";
2031 case Token::Kind::TK_SHREQ: return ">>=";
2032 case Token::Kind::TK_LOGICALANDEQ: return "&&=";
2033 case Token::Kind::TK_LOGICALOREQ: return "||=";
2034 case Token::Kind::TK_LOGICALXOREQ: return "^^=";
2035 case Token::Kind::TK_BITWISEANDEQ: return "&=";
2036 case Token::Kind::TK_BITWISEOREQ: return "|=";
2037 case Token::Kind::TK_BITWISEXOREQ: return "^=";
2038 case Token::Kind::TK_PLUSPLUS: return "++";
2039 case Token::Kind::TK_MINUSMINUS: return "--";
2040 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002041 default:
Brian Osman401a0092020-09-10 14:47:24 -04002042 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002043 }
2044}
2045
2046
2047bool Compiler::IsAssignment(Token::Kind op) {
2048 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002049 case Token::Kind::TK_EQ: // fall through
2050 case Token::Kind::TK_PLUSEQ: // fall through
2051 case Token::Kind::TK_MINUSEQ: // fall through
2052 case Token::Kind::TK_STAREQ: // fall through
2053 case Token::Kind::TK_SLASHEQ: // fall through
2054 case Token::Kind::TK_PERCENTEQ: // fall through
2055 case Token::Kind::TK_SHLEQ: // fall through
2056 case Token::Kind::TK_SHREQ: // fall through
2057 case Token::Kind::TK_BITWISEOREQ: // fall through
2058 case Token::Kind::TK_BITWISEXOREQ: // fall through
2059 case Token::Kind::TK_BITWISEANDEQ: // fall through
2060 case Token::Kind::TK_LOGICALOREQ: // fall through
2061 case Token::Kind::TK_LOGICALXOREQ: // fall through
2062 case Token::Kind::TK_LOGICALANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002063 return true;
2064 default:
2065 return false;
2066 }
2067}
2068
Brian Osman401a0092020-09-10 14:47:24 -04002069Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
2070 switch (op) {
2071 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
2072 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
2073 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
2074 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
2075 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
2076 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
2077 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
2078 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
2079 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
2080 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
2081 case Token::Kind::TK_LOGICALOREQ: return Token::Kind::TK_LOGICALOR;
2082 case Token::Kind::TK_LOGICALXOREQ: return Token::Kind::TK_LOGICALXOR;
2083 case Token::Kind::TK_LOGICALANDEQ: return Token::Kind::TK_LOGICALAND;
2084 default: return op;
2085 }
2086}
2087
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002088Position Compiler::position(int offset) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002089 SkASSERT(fSource);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002090 int line = 1;
2091 int column = 1;
2092 for (int i = 0; i < offset; i++) {
2093 if ((*fSource)[i] == '\n') {
2094 ++line;
2095 column = 1;
2096 }
2097 else {
2098 ++column;
2099 }
2100 }
2101 return Position(line, column);
2102}
2103
2104void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002105 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002106 Position pos = this->position(offset);
2107 fErrorText += "error: " + to_string(pos.fLine) + ": " + msg.c_str() + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07002108}
2109
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002110String Compiler::errorText() {
Ethan Nicholas00543112018-07-31 09:44:36 -04002111 this->writeErrorCount();
2112 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002113 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07002114 return result;
2115}
2116
2117void Compiler::writeErrorCount() {
2118 if (fErrorCount) {
2119 fErrorText += to_string(fErrorCount) + " error";
2120 if (fErrorCount > 1) {
2121 fErrorText += "s";
2122 }
2123 fErrorText += "\n";
2124 }
2125}
2126
John Stilesa6841be2020-08-06 14:11:56 -04002127} // namespace SkSL