blob: 1530477d33fc5afe236216b6b7d957255d52846b [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"
Brian Osmanb06301e2020-11-06 11:45:36 -050063#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050064#include "src/sksl/generated/sksl_runtime.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)
John Stiles7b920442020-12-17 10:43:41 -050090 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -050091 , 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 Osmanc0f2b642020-12-22 13:35:55 -0500113 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500114
Brian Osmanb06301e2020-11-06 11:45:36 -0500115 TYPE(Half2x2), TYPE(Half2x3), TYPE(Half2x4),
116 TYPE(Half3x2), TYPE(Half3x3), TYPE(Half3x4),
117 TYPE(Half4x2), TYPE(Half4x3), TYPE(Half4x4),
ethannicholasb3058bd2016-07-01 08:22:01 -0700118
Brian Osmanb06301e2020-11-06 11:45:36 -0500119 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenUType), TYPE(GenBType),
Brian Osmanc0f2b642020-12-22 13:35:55 -0500120 TYPE(SquareMat), TYPE(SquareHMat), TYPE(Vec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500121 TYPE(GVec), TYPE(GVec2), TYPE(GVec3), TYPE(GVec4),
122 TYPE(HVec), TYPE(IVec), TYPE(UVec), TYPE(SVec), TYPE(USVec),
123 TYPE(ByteVec), TYPE(UByteVec), TYPE(BVec),
124
125 TYPE(FragmentProcessor),
126 };
127
128 const SkSL::Symbol* privateTypes[] = {
Brian Osmanc0f2b642020-12-22 13:35:55 -0500129 TYPE(Float2x3), TYPE(Float2x4),
130 TYPE(Float3x2), TYPE(Float3x4),
131 TYPE(Float4x2), TYPE(Float4x3),
132
133 TYPE(Mat), TYPE(HMat),
134
Brian Osmanb06301e2020-11-06 11:45:36 -0500135 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
136 TYPE(SamplerExternalOES),
137 TYPE(SamplerCube),
138 TYPE(Sampler2DRect),
139 TYPE(Sampler1DArray), TYPE(Sampler2DArray), TYPE(SamplerCubeArray),
140 TYPE(SamplerBuffer),
141 TYPE(Sampler2DMS), TYPE(Sampler2DMSArray),
142
143 TYPE(ISampler2D),
144 TYPE(Image2D), TYPE(IImage2D),
145 TYPE(SubpassInput), TYPE(SubpassInputMS),
146
147 TYPE(GSampler1D), TYPE(GSampler2D), TYPE(GSampler3D),
148 TYPE(GSamplerCube),
149 TYPE(GSampler2DRect),
150 TYPE(GSampler1DArray), TYPE(GSampler2DArray), TYPE(GSamplerCubeArray),
151 TYPE(GSamplerBuffer),
152 TYPE(GSampler2DMS), TYPE(GSampler2DMSArray),
153
154 TYPE(Sampler1DShadow), TYPE(Sampler2DShadow), TYPE(SamplerCubeShadow),
155 TYPE(Sampler2DRectShadow),
156 TYPE(Sampler1DArrayShadow), TYPE(Sampler2DArrayShadow), TYPE(SamplerCubeArrayShadow),
157
158 TYPE(GSampler2DArrayShadow), TYPE(GSamplerCubeArrayShadow),
159 TYPE(Sampler),
160 TYPE(Texture2D),
161 };
162
163 for (const SkSL::Symbol* type : rootTypes) {
164 fRootSymbolTable->addWithoutOwnership(type);
165 }
166 for (const SkSL::Symbol* type : privateTypes) {
167 fPrivateSymbolTable->addWithoutOwnership(type);
168 }
169
170#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700171
Brian Osman3887a012020-09-30 13:22:27 -0400172 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
173 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500174 fPrivateSymbolTable->add(
175 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500176 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500177 "sk_Caps",
178 fContext->fSkCaps_Type.get(),
179 /*builtin=*/false,
180 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500181
Brian Osman3d87e9f2020-10-08 11:50:22 -0400182 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500183 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700184}
185
John Stilesdd13dba2020-10-29 10:45:34 -0400186Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700187
Brian Osman56269982020-11-20 12:38:07 -0500188const ParsedModule& Compiler::loadGPUModule() {
189 if (!fGPUModule.fSymbols) {
190 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
191 }
192 return fGPUModule;
193}
194
195const ParsedModule& Compiler::loadFragmentModule() {
196 if (!fFragmentModule.fSymbols) {
197 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag),
198 this->loadGPUModule());
199 }
200 return fFragmentModule;
201}
202
203const ParsedModule& Compiler::loadVertexModule() {
204 if (!fVertexModule.fSymbols) {
205 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert),
206 this->loadGPUModule());
207 }
208 return fVertexModule;
209}
210
Brian Osman88cda172020-10-09 12:05:16 -0400211const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400212 if (!fGeometryModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500213 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom),
214 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400215 }
Brian Osman88cda172020-10-09 12:05:16 -0400216 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400217}
218
Brian Osman88cda172020-10-09 12:05:16 -0400219const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400220 if (!fFPModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500221 fFPModule = this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp),
222 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400223 }
Brian Osman88cda172020-10-09 12:05:16 -0400224 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400225}
226
Brian Osmanb06301e2020-11-06 11:45:36 -0500227const ParsedModule& Compiler::loadPublicModule() {
228 if (!fPublicModule.fSymbols) {
229 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
230 }
231 return fPublicModule;
232}
233
Brian Osman91946752020-12-21 13:20:40 -0500234const ParsedModule& Compiler::loadRuntimeEffectModule() {
235 if (!fRuntimeEffectModule.fSymbols) {
236 fRuntimeEffectModule = this->parseModule(Program::kRuntimeEffect_Kind, MODULE_DATA(runtime),
237 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400238
Brian Osman91946752020-12-21 13:20:40 -0500239 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
240 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fFragmentProcessor_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400241
Brian Osman91946752020-12-21 13:20:40 -0500242 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fFloat2_Type.get());
243 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fFloat3_Type.get());
244 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fFloat4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400245
Brian Osman91946752020-12-21 13:20:40 -0500246 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fBool2_Type.get());
247 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fBool3_Type.get());
248 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fBool4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400249
Brian Osman91946752020-12-21 13:20:40 -0500250 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fFloat2x2_Type.get());
251 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fFloat3x3_Type.get());
252 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fFloat4x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400253
Brian Osman91946752020-12-21 13:20:40 -0500254 fRuntimeEffectModule.fSymbols->addAlias("mat2x2", fContext->fFloat2x2_Type.get());
255 fRuntimeEffectModule.fSymbols->addAlias("mat2x3", fContext->fFloat2x3_Type.get());
256 fRuntimeEffectModule.fSymbols->addAlias("mat2x4", fContext->fFloat2x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400257
Brian Osman91946752020-12-21 13:20:40 -0500258 fRuntimeEffectModule.fSymbols->addAlias("mat3x2", fContext->fFloat3x2_Type.get());
259 fRuntimeEffectModule.fSymbols->addAlias("mat3x3", fContext->fFloat3x3_Type.get());
260 fRuntimeEffectModule.fSymbols->addAlias("mat3x4", fContext->fFloat3x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400261
Brian Osman91946752020-12-21 13:20:40 -0500262 fRuntimeEffectModule.fSymbols->addAlias("mat4x2", fContext->fFloat4x2_Type.get());
263 fRuntimeEffectModule.fSymbols->addAlias("mat4x3", fContext->fFloat4x3_Type.get());
264 fRuntimeEffectModule.fSymbols->addAlias("mat4x4", fContext->fFloat4x4_Type.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400265 }
Brian Osman91946752020-12-21 13:20:40 -0500266 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400267}
268
Brian Osman88cda172020-10-09 12:05:16 -0400269const ParsedModule& Compiler::loadInterpreterModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400270 if (!fInterpreterModule.fSymbols) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500271 fInterpreterModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(interp),
272 this->loadPublicModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400273 }
Brian Osman88cda172020-10-09 12:05:16 -0400274 return fInterpreterModule;
275}
276
277const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
278 switch (kind) {
Brian Osman91946752020-12-21 13:20:40 -0500279 case Program::kVertex_Kind: return this->loadVertexModule(); break;
280 case Program::kFragment_Kind: return this->loadFragmentModule(); break;
281 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
282 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
283 case Program::kRuntimeEffect_Kind: return this->loadRuntimeEffectModule(); break;
284 case Program::kGeneric_Kind: return this->loadInterpreterModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400285 }
286 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400287}
288
Brian Osman3d87e9f2020-10-08 11:50:22 -0400289LoadedModule Compiler::loadModule(Program::Kind kind,
290 ModuleData data,
291 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400292 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500293 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
294 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
295 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
296 // like samplers or textures. Today, 'Private' does contain the union of all known types,
297 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
298 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
299 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400300 }
301
302#if defined(SKSL_STANDALONE)
303 SkASSERT(data.fPath);
304 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400305 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
306 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400307 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400308 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400309 abort();
310 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400311 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400312 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400313 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400314 SkASSERT(fIRGenerator->fCanInline);
315 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400316 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500317 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500318 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500319 /*isBuiltinCode=*/true, source->c_str(), source->length(),
320 /*externalValues=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400321 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500322 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400323 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400324 if (this->fErrorCount) {
325 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400326 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400327 }
Brian Osman88cda172020-10-09 12:05:16 -0400328 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400329#else
330 SkASSERT(data.fData && (data.fSize != 0));
331 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
332 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500333 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400334 fModifiers.push_back(fIRGenerator->releaseModifiers());
335#endif
336
337 return module;
338}
339
340ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500341 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
342 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400343
344 // For modules that just declare (but don't define) intrinsic functions, there will be no new
345 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500346 if (module.fElements.empty()) {
347 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400348 }
349
350 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
351
352 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
353 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500354 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400355 switch (element->kind()) {
356 case ProgramElement::Kind::kFunction: {
357 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400358 SkASSERT(f.declaration().isBuiltin());
359 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400360 break;
361 }
John Stiles569249b2020-11-03 12:18:22 -0500362 case ProgramElement::Kind::kFunctionPrototype: {
363 // These are already in the symbol table.
364 break;
365 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400366 case ProgramElement::Kind::kEnum: {
367 const Enum& e = element->as<Enum>();
368 SkASSERT(e.isBuiltin());
369 intrinsics->insertOrDie(e.typeName(), std::move(element));
370 break;
371 }
372 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400373 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
374 const Variable& var = global.declaration()->as<VarDeclaration>().var();
375 SkASSERT(var.isBuiltin());
376 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400377 break;
378 }
379 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400380 const Variable& var = element->as<InterfaceBlock>().variable();
381 SkASSERT(var.isBuiltin());
382 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400383 break;
384 }
385 default:
386 printf("Unsupported element: %s\n", element->description().c_str());
387 SkASSERT(false);
388 break;
389 }
390 }
391
Brian Osman0006ad02020-11-18 15:38:39 -0500392 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400393}
394
ethannicholas22f939e2016-10-13 13:25:34 -0700395// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500396void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
397 DefinitionMap* definitions) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400398 switch (lvalue->kind()) {
399 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -0400400 const Variable& var = *lvalue->as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400401 if (var.storage() == Variable::Storage::kLocal) {
John Stiles796cdb72020-10-08 12:06:53 -0400402 definitions->set(&var, expr);
ethannicholas22f939e2016-10-13 13:25:34 -0700403 }
404 break;
405 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400406 case Expression::Kind::kSwizzle:
ethannicholas22f939e2016-10-13 13:25:34 -0700407 // We consider the variable written to as long as at least some of its components have
408 // been written to. This will lead to some false negatives (we won't catch it if you
409 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400410 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
411 // 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 -0700412 // more complicated whole-program analysis. This is probably good enough.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400413 this->addDefinition(lvalue->as<Swizzle>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400414 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700415 definitions);
416 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400417 case Expression::Kind::kIndex:
ethannicholas22f939e2016-10-13 13:25:34 -0700418 // see comments in Swizzle
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400419 this->addDefinition(lvalue->as<IndexExpression>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400420 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700421 definitions);
422 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400423 case Expression::Kind::kFieldAccess:
ethannicholas22f939e2016-10-13 13:25:34 -0700424 // see comments in Swizzle
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400425 this->addDefinition(lvalue->as<FieldAccess>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400426 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700427 definitions);
428 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400429 case Expression::Kind::kTernary:
Ethan Nicholasa583b812018-01-18 13:32:11 -0500430 // To simplify analysis, we just pretend that we write to both sides of the ternary.
431 // This allows for false positives (meaning we fail to detect that a variable might not
432 // have been assigned), but is preferable to false negatives.
Ethan Nicholasdd218162020-10-08 05:48:01 -0400433 this->addDefinition(lvalue->as<TernaryExpression>().ifTrue().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400434 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500435 definitions);
Ethan Nicholasdd218162020-10-08 05:48:01 -0400436 this->addDefinition(lvalue->as<TernaryExpression>().ifFalse().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400437 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500438 definitions);
439 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400440 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400441 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700442 default:
443 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400444 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700445 }
446}
447
448// add local variables defined by this node to the set
John Stiles796cdb72020-10-08 12:06:53 -0400449void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) {
John Stiles70025e52020-09-28 16:08:58 -0400450 if (node.isExpression()) {
451 Expression* expr = node.expression()->get();
452 switch (expr->kind()) {
453 case Expression::Kind::kBinary: {
454 BinaryExpression* b = &expr->as<BinaryExpression>();
455 if (b->getOperator() == Token::Kind::TK_EQ) {
John Stiles2d4f9592020-10-30 10:29:12 -0400456 this->addDefinition(b->left().get(), &b->right(), definitions);
John Stiles70025e52020-09-28 16:08:58 -0400457 } else if (Compiler::IsAssignment(b->getOperator())) {
458 this->addDefinition(
John Stiles2d4f9592020-10-30 10:29:12 -0400459 b->left().get(),
John Stiles70025e52020-09-28 16:08:58 -0400460 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
461 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500462
ethannicholas22f939e2016-10-13 13:25:34 -0700463 }
John Stiles70025e52020-09-28 16:08:58 -0400464 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700465 }
John Stiles70025e52020-09-28 16:08:58 -0400466 case Expression::Kind::kFunctionCall: {
467 const FunctionCall& c = expr->as<FunctionCall>();
Brian Osman5bf3e202020-10-13 10:34:18 -0400468 const std::vector<const Variable*>& parameters = c.function().parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400469 for (size_t i = 0; i < parameters.size(); ++i) {
470 if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stiles70025e52020-09-28 16:08:58 -0400471 this->addDefinition(
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400472 c.arguments()[i].get(),
John Stiles70025e52020-09-28 16:08:58 -0400473 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
474 definitions);
475 }
476 }
477 break;
478 }
479 case Expression::Kind::kPrefix: {
480 const PrefixExpression* p = &expr->as<PrefixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400481 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
482 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400483 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400484 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400485 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
486 definitions);
487 }
488 break;
489 }
490 case Expression::Kind::kPostfix: {
491 const PostfixExpression* p = &expr->as<PostfixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400492 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
493 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400494 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400495 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400496 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
497 definitions);
498 }
499 break;
500 }
501 case Expression::Kind::kVariableReference: {
502 const VariableReference* v = &expr->as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400503 if (v->refKind() != VariableReference::RefKind::kRead) {
John Stiles70025e52020-09-28 16:08:58 -0400504 this->addDefinition(
505 v,
506 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
507 definitions);
508 }
509 break;
510 }
511 default:
512 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700513 }
John Stiles70025e52020-09-28 16:08:58 -0400514 } else if (node.isStatement()) {
515 Statement* stmt = node.statement()->get();
516 if (stmt->is<VarDeclaration>()) {
517 VarDeclaration& vd = stmt->as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400518 if (vd.value()) {
519 definitions->set(&vd.var(), &vd.value());
ethannicholas22f939e2016-10-13 13:25:34 -0700520 }
ethannicholas22f939e2016-10-13 13:25:34 -0700521 }
522 }
523}
524
John Stilese6150002020-10-05 12:03:53 -0400525void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700526 BasicBlock& block = cfg->fBlocks[blockId];
527
528 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500529 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700530 for (const BasicBlock::Node& n : block.fNodes) {
531 this->addDefinitions(n, &after);
532 }
533
534 // propagate definitions to exits
535 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400536 if (exitId == blockId) {
537 continue;
538 }
ethannicholas22f939e2016-10-13 13:25:34 -0700539 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles796cdb72020-10-08 12:06:53 -0400540 after.foreach([&](const Variable* var, std::unique_ptr<Expression>** e1Ptr) {
541 std::unique_ptr<Expression>* e1 = *e1Ptr;
542 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
543 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400544 // exit has no definition for it, just copy it and reprocess exit block
545 processedSet->reset(exitId);
John Stiles796cdb72020-10-08 12:06:53 -0400546 exit.fBefore[var] = e1;
ethannicholas22f939e2016-10-13 13:25:34 -0700547 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500548 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400549 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700550 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400551 // definition has changed, merge and reprocess the exit block
552 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500553 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400554 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500555 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400556 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500557 }
ethannicholas22f939e2016-10-13 13:25:34 -0700558 }
559 }
John Stiles796cdb72020-10-08 12:06:53 -0400560 });
ethannicholas22f939e2016-10-13 13:25:34 -0700561 }
562}
563
564// returns a map which maps all local variables in the function to null, indicating that their value
565// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500566static DefinitionMap compute_start_state(const CFG& cfg) {
567 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400568 for (const auto& block : cfg.fBlocks) {
569 for (const auto& node : block.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -0400570 if (node.isStatement()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400571 const Statement* s = node.statement()->get();
Brian Osmanc0213602020-10-06 14:43:32 -0400572 if (s->is<VarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400573 result[&s->as<VarDeclaration>().var()] = nullptr;
ethannicholas22f939e2016-10-13 13:25:34 -0700574 }
575 }
576 }
577 }
578 return result;
579}
580
Ethan Nicholascb670962017-04-20 19:31:52 -0400581/**
582 * Returns true if assigning to this lvalue has no effect.
583 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400584static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400585 switch (lvalue.kind()) {
586 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400587 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400588 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400589 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400590 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400591 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400592 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400593 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400594 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400595 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400596 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400597 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400598 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400599 return !t.test()->hasSideEffects() &&
600 is_dead(*t.ifTrue(), usage) &&
601 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500602 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400603 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400604 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400605 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500606#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400607 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500608#endif
609 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400610 }
611}
ethannicholas22f939e2016-10-13 13:25:34 -0700612
Ethan Nicholascb670962017-04-20 19:31:52 -0400613/**
614 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
615 * to a dead target and lack of side effects on the left hand side.
616 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400617static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400618 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400619 return false;
620 }
John Stiles2d4f9592020-10-30 10:29:12 -0400621 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400622}
623
624void Compiler::computeDataFlow(CFG* cfg) {
625 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400626
627 // We set bits in the "processed" set after a block has been scanned.
628 SkBitSet processedSet(cfg->fBlocks.size());
629 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
630 processedSet.set(*blockId);
631 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700632 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400633}
634
635/**
636 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
637 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
638 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
639 * need to be regenerated).
640 */
John Stilesafbf8992020-08-18 10:08:21 -0400641static bool try_replace_expression(BasicBlock* b,
642 std::vector<BasicBlock::Node>::iterator* iter,
643 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400644 std::unique_ptr<Expression>* target = (*iter)->expression();
645 if (!b->tryRemoveExpression(iter)) {
646 *target = std::move(*newExpression);
647 return false;
648 }
649 *target = std::move(*newExpression);
650 return b->tryInsertExpression(iter, target);
651}
652
653/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400654 * Returns true if the expression is a constant numeric literal with the specified value, or a
655 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400656 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400657template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400658static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400659 switch (expr.kind()) {
660 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400661 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400662
Ethan Nicholase6592142020-09-08 10:22:09 -0400663 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400664 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400665
Ethan Nicholase6592142020-09-08 10:22:09 -0400666 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400667 const Constructor& constructor = expr.as<Constructor>();
668 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400669 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400670 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400671 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500672 if (constructor.componentType().isFloat()) {
673 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400674 if (constructor.getFVecComponent(i) != value) {
675 return false;
676 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500677 }
678 return true;
679 } else if (constructor.componentType().isInteger()) {
680 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400681 if (constructor.getIVecComponent(i) != value) {
682 return false;
683 }
684 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500685 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400686 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500687 // Other types (e.g. boolean) might occur, but aren't supported here.
688 return false;
John Stiles9d944232020-08-19 09:56:49 -0400689
Ethan Nicholase6592142020-09-08 10:22:09 -0400690 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400691 SkASSERT(constructor.arguments().size() == 1);
692 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400693
694 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400695 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400696 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400697 }
698 return false;
699 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400700 default:
701 return false;
702 }
703}
704
705/**
706 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
707 * and CFG structures).
708 */
John Stilesafbf8992020-08-18 10:08:21 -0400709static void delete_left(BasicBlock* b,
710 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400711 Compiler::OptimizationContext* optimizationContext) {
712 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400713 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400714 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400715 Expression& left = *bin.left();
716 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400717 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400718 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400719 if (bin.getOperator() == Token::Kind::TK_EQ) {
720 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400721 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400722 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400723 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400724 // Remove references within LHS.
725 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400726 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400727 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400728 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400729 return;
730 }
731 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400732 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400733 return;
734 }
735 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400736 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400737 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400738 return;
739 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400740 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400741 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400742}
743
744/**
745 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
746 * CFG structures).
747 */
John Stilesafbf8992020-08-18 10:08:21 -0400748static void delete_right(BasicBlock* b,
749 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400750 Compiler::OptimizationContext* optimizationContext) {
751 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400752 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400753 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400754 std::unique_ptr<Expression>& leftPointer = bin.left();
755 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400756 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400757 // Remove references within RHS.
758 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400759 if (!b->tryRemoveExpressionBefore(iter, &right)) {
760 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400761 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400762 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400763 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400764 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400765 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400766 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400767 return;
768 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400769 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400770 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400771 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400772 return;
773 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400774 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400775 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400776}
777
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400778/**
779 * Constructs the specified type using a single argument.
780 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400781static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400782 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400783 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400784 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400785 return result;
786}
787
788/**
789 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
790 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
791 */
792static void vectorize(BasicBlock* b,
793 std::vector<BasicBlock::Node>::iterator* iter,
794 const Type& type,
795 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400796 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400797 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500798 SkASSERT(type.isVector());
799 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400800 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400801 std::unique_ptr<Expression>* target = (*iter)->expression();
802 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400803 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400804 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400805 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400806 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400807 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400808 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400809 }
810 }
811}
812
813/**
814 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
815 * left to yield vec<n>(x).
816 */
817static void vectorize_left(BasicBlock* b,
818 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400819 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400820 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400821 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400822 optimizationContext->fUsage->remove(bin.right().get());
823 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400824}
825
826/**
827 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
828 * right to yield vec<n>(y).
829 */
830static void vectorize_right(BasicBlock* b,
831 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400832 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400833 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400834 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400835 optimizationContext->fUsage->remove(bin.left().get());
836 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400837}
838
839// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400840static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400841 switch (expr.kind()) {
842 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400843 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400844 break;
845 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400846 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400847 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400848 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400849 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400850 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400851 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400852 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400853 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400854 break;
855 default:
856 ABORT("shouldn't be writing to this kind of expression\n");
857 break;
858 }
859}
860
Ethan Nicholascb670962017-04-20 19:31:52 -0400861void Compiler::simplifyExpression(DefinitionMap& definitions,
862 BasicBlock& b,
863 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400864 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400865 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400866 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500867
Ethan Nicholascb670962017-04-20 19:31:52 -0400868 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400869 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
870 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400871 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400872 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400873 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400874 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400875 // Remove references within 'expr', add references within 'optimized'
876 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400877 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400878 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400879 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400880 }
John Stiles70025e52020-09-28 16:08:58 -0400881 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400882 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400883 }
884 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400885 switch (expr->kind()) {
886 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400887 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400888 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400889 if (ref.refKind() != VariableReference::RefKind::kWrite &&
890 ref.refKind() != VariableReference::RefKind::kPointer &&
891 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400892 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
893 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000894 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400895 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400896 }
897 break;
898 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400899 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400900 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400901 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400902 // ternary has a constant test, replace it with either the true or
903 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400904 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400905 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400906 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400907 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400908 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400909 optimizationContext->fUpdated = true;
910 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400911 }
912 break;
913 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400914 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400915 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400916 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400917 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400918 break;
919 }
John Stiles2d4f9592020-10-30 10:29:12 -0400920 Expression& left = *bin->left();
921 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400922 const Type& leftType = left.type();
923 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400924 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500925 if ((!leftType.isScalar() && !leftType.isVector()) ||
926 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400927 break;
928 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400929 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400930 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400931 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500932 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400933 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400934 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400935 } else {
936 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400937 // 1 * float4(x) -> float4(x)
938 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400939 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400940 }
941 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400942 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500943 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400944 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400945 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400946 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400947 } else {
948 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400949 // float4(0) * x -> float4(0)
950 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400951 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400952 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500953 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400954 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400955 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400956 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500957 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400958 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400959 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400960 } else {
961 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400962 // float4(x) * 1 -> float4(x)
963 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400964 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400965 }
966 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400967 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500968 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400969 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400970 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400971 } else {
972 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400973 // x * float4(0) -> float4(0)
974 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400975 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400976 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500977 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400978 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400979 }
980 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400981 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400982 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500983 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400984 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400985 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400986 } else {
987 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400988 // 0 + float4(x) -> float4(x)
989 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400990 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400991 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400992 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500993 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400994 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400995 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400996 } else {
997 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400998 // float4(x) + 0 -> float4(x)
999 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001000 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001001 }
Ethan Nicholas56e42712017-04-21 10:23:37 -04001002 }
1003 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001004 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001005 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -05001006 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001007 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001008 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001009 } else {
1010 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001011 // float4(x) - 0 -> float4(x)
1012 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001013 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001014 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001015 }
1016 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001017 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001018 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -05001019 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001020 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001021 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001022 } else {
1023 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001024 // float4(x) / 1 -> float4(x)
1025 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001026 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001027 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001028 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -05001029 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001030 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001031 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001032 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001033 } else {
1034 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001035 // float4(0) / x -> float4(0)
1036 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001037 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001038 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001039 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001040 }
1041 }
1042 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001043 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001044 if (is_constant(right, 0)) {
1045 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001046 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001047 }
1048 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001049 case Token::Kind::TK_MINUSEQ:
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_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001056 if (is_constant(right, 1)) {
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_SLASHEQ:
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 Nicholascb670962017-04-20 19:31:52 -04001065 }
1066 break;
1067 default:
1068 break;
1069 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001070 break;
1071 }
John Stilesf5c1d042020-11-21 23:26:07 -05001072 case Expression::Kind::kConstructor: {
1073 // Find constructors embedded inside constructors and flatten them out where possible.
1074 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
1075 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
1076 // Leave single-argument constructors alone, though. These might be casts or splats.
1077 Constructor& c = expr->as<Constructor>();
1078 if (c.type().columns() > 1) {
1079 // Inspect each constructor argument to see if it's a candidate for flattening.
1080 // Remember matched arguments in a bitfield, "argsToOptimize".
1081 int argsToOptimize = 0;
1082 int currBit = 1;
1083 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1084 if (arg->is<Constructor>()) {
1085 Constructor& inner = arg->as<Constructor>();
1086 if (inner.arguments().size() > 1 &&
1087 inner.type().componentType() == c.type().componentType()) {
1088 argsToOptimize |= currBit;
1089 }
1090 }
1091 currBit <<= 1;
1092 }
1093 if (argsToOptimize) {
1094 // We found at least one argument that could be flattened out. Re-walk the
1095 // constructor args and flatten the candidates we found during our initial pass.
1096 ExpressionArray flattened;
1097 flattened.reserve_back(c.type().columns());
1098 currBit = 1;
1099 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1100 if (argsToOptimize & currBit) {
1101 Constructor& inner = arg->as<Constructor>();
1102 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
1103 flattened.push_back(innerArg->clone());
1104 }
1105 } else {
1106 flattened.push_back(arg->clone());
1107 }
1108 currBit <<= 1;
1109 }
1110 auto optimized = std::unique_ptr<Expression>(
1111 new Constructor(c.fOffset, &c.type(), std::move(flattened)));
1112 // No fUsage change; no references have been added or removed anywhere.
1113 optimizationContext->fUpdated = true;
1114 if (!try_replace_expression(&b, iter, &optimized)) {
1115 optimizationContext->fNeedsRescan = true;
1116 return;
1117 }
1118 SkASSERT((*iter)->isExpression());
1119 break;
1120 }
1121 }
1122 break;
1123 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001124 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001125 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -05001126 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001127 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001128 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001129 for (int i = 0; i < (int) s.components().size(); ++i) {
1130 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001131 identity = false;
1132 break;
1133 }
1134 }
1135 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001136 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001137 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001138 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001139 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001140 return;
1141 }
John Stiles70025e52020-09-28 16:08:58 -04001142 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001143 break;
1144 }
1145 }
John Stiles108bbe22020-11-18 11:10:38 -05001146 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1147 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001148 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001149 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001150 for (int c : s.components()) {
1151 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001152 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001153 optimizationContext->fUpdated = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001154 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001155 final));
John Stiles108bbe22020-11-18 11:10:38 -05001156 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001157 if (!try_replace_expression(&b, iter, &replacement)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001158 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001159 return;
1160 }
John Stiles70025e52020-09-28 16:08:58 -04001161 SkASSERT((*iter)->isExpression());
John Stiles108bbe22020-11-18 11:10:38 -05001162 break;
1163 }
1164 // Optimize swizzles of constructors.
1165 if (s.base()->is<Constructor>()) {
1166 Constructor& base = s.base()->as<Constructor>();
1167 std::unique_ptr<Expression> replacement;
1168 const Type& componentType = base.type().componentType();
1169 int swizzleSize = s.components().size();
1170
1171 // The IR generator has already converted any zero/one swizzle components into
1172 // constructors containing zero/one args. Confirm that this is true by checking that
1173 // our swizzle components are all `xyzw` (values 0 through 3).
1174 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1175 [](int8_t c) { return c >= 0 && c <= 3; }));
1176
John Stiles9aeed132020-11-24 17:36:06 -05001177 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001178 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1179 // components don't actually matter since all fields are the same.
1180 ExpressionArray newArgs;
1181 newArgs.push_back(base.arguments().front()->clone());
1182 replacement = std::make_unique<Constructor>(
1183 base.fOffset,
1184 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1185 std::move(newArgs));
1186
John Stilesa60ac0c2020-12-22 08:59:51 -05001187 // We're replacing an expression with a cloned version; we'll need a rescan.
1188 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1189 // reference counts.
1190 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001191 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001192 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001193 break;
1194 }
1195
John Stiles0777ac42020-11-19 11:06:47 -05001196 // Swizzles can duplicate some elements and discard others, e.g.
1197 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1198 // - Expressions with side effects need to occur exactly once, even if they
1199 // would otherwise be swizzle-eliminated
1200 // - Non-trivial expressions should not be repeated, but elimination is OK.
1201 //
1202 // Look up the argument for the constructor at each index. This is typically simple
1203 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1204 // seems. This example would result in:
1205 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1206 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1207 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1208 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1209 struct ConstructorArgMap {
1210 int8_t fArgIndex;
1211 int8_t fComponent;
1212 };
1213
1214 int numConstructorArgs = base.type().columns();
1215 ConstructorArgMap argMap[4] = {};
1216 int writeIdx = 0;
1217 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1218 const Expression& expr = *base.arguments()[argIdx];
1219 int argWidth = expr.type().columns();
1220 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1221 argMap[writeIdx].fArgIndex = argIdx;
1222 argMap[writeIdx].fComponent = componentIdx;
1223 ++writeIdx;
1224 }
1225 }
1226 SkASSERT(writeIdx == numConstructorArgs);
1227
1228 // Count up the number of times each constructor argument is used by the
1229 // swizzle.
1230 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1231 // - bar.yz is referenced 3 times, by `.x_xy`
1232 // - half(foo) is referenced 1 time, by `._w__`
1233 int8_t exprUsed[4] = {};
1234 for (int c : s.components()) {
1235 exprUsed[argMap[c].fArgIndex]++;
1236 }
1237
1238 bool safeToOptimize = true;
1239 for (int index = 0; index < numConstructorArgs; ++index) {
1240 int8_t constructorArgIndex = argMap[index].fArgIndex;
1241 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1242
1243 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001244 if (exprUsed[constructorArgIndex] > 1 &&
1245 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001246 safeToOptimize = false;
1247 break;
1248 }
1249 // Check that side-effect-bearing expressions are swizzled in exactly once.
1250 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1251 safeToOptimize = false;
1252 break;
1253 }
1254 }
1255
1256 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001257 struct ReorderedArgument {
1258 int8_t fArgIndex;
1259 ComponentArray fComponents;
1260 };
1261 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001262 for (int c : s.components()) {
1263 const ConstructorArgMap& argument = argMap[c];
1264 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1265
John Stiles9aeed132020-11-24 17:36:06 -05001266 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001267 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001268 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001269 reorderedArgs.push_back({argument.fArgIndex,
1270 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001271 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001272 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001273 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001274 if (reorderedArgs.empty() ||
1275 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1276 // This can't be combined with the previous argument. Add a new one.
1277 reorderedArgs.push_back({argument.fArgIndex,
1278 ComponentArray{argument.fComponent}});
1279 } else {
1280 // Since we know this argument uses components, it should already
1281 // have at least one component set.
1282 SkASSERT(!reorderedArgs.back().fComponents.empty());
1283 // Build up the current argument with one more component.
1284 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1285 }
John Stiles0777ac42020-11-19 11:06:47 -05001286 }
1287 }
John Stilesd9076cb2020-11-19 12:18:36 -05001288
1289 // Convert our reordered argument list to an actual array of expressions, with
1290 // the new order and any new inner swizzles that need to be applied. Note that
1291 // we expect followup passes to clean up the inner swizzles.
1292 ExpressionArray newArgs;
1293 newArgs.reserve_back(swizzleSize);
1294 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1295 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1296 if (reorderedArg.fComponents.empty()) {
1297 newArgs.push_back(baseArg.clone());
1298 } else {
1299 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1300 reorderedArg.fComponents));
1301 }
1302 }
1303
1304 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001305 replacement = std::make_unique<Constructor>(
1306 base.fOffset,
1307 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1308 std::move(newArgs));
1309
John Stilesa60ac0c2020-12-22 08:59:51 -05001310 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001311 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001312
1313 // We're replacing an expression with a cloned version; we'll need a rescan.
1314 try_replace_expression(&b, iter, &replacement);
1315 optimizationContext->fUpdated = true;
1316 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001317 }
John Stiles108bbe22020-11-18 11:10:38 -05001318 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001319 }
John Stiles30212b72020-06-11 17:55:07 -04001320 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001321 }
1322 default:
1323 break;
1324 }
1325}
1326
John Stiles92219b42020-06-15 12:32:24 -04001327// Returns true if this statement could potentially execute a break at the current level. We ignore
1328// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001329static bool contains_conditional_break(Statement& stmt) {
1330 class ContainsConditionalBreak : public ProgramVisitor {
1331 public:
1332 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001333 switch (stmt.kind()) {
1334 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001335 return this->INHERITED::visitStatement(stmt);
1336
Ethan Nicholase6592142020-09-08 10:22:09 -04001337 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001338 return fInConditional > 0;
1339
Ethan Nicholase6592142020-09-08 10:22:09 -04001340 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001341 ++fInConditional;
1342 bool result = this->INHERITED::visitStatement(stmt);
1343 --fInConditional;
1344 return result;
1345 }
1346
1347 default:
1348 return false;
1349 }
1350 }
1351
1352 int fInConditional = 0;
1353 using INHERITED = ProgramVisitor;
1354 };
1355
1356 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001357}
1358
Ethan Nicholas5005a222018-08-24 13:06:27 -04001359// returns true if this statement definitely executes a break at the current level (we ignore
1360// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001361static bool contains_unconditional_break(Statement& stmt) {
1362 class ContainsUnconditionalBreak : public ProgramVisitor {
1363 public:
1364 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001365 switch (stmt.kind()) {
1366 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001367 return this->INHERITED::visitStatement(stmt);
1368
Ethan Nicholase6592142020-09-08 10:22:09 -04001369 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001370 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001371
1372 default:
1373 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001374 }
John Stilesb92641c2020-08-31 18:09:01 -04001375 }
John Stiles92219b42020-06-15 12:32:24 -04001376
John Stilesb92641c2020-08-31 18:09:01 -04001377 using INHERITED = ProgramVisitor;
1378 };
John Stiles92219b42020-06-15 12:32:24 -04001379
John Stilesb92641c2020-08-31 18:09:01 -04001380 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001381}
1382
John Stiles8f2a0cf2020-10-13 12:48:21 -04001383static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001384 switch (stmt->kind()) {
1385 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001386 // Recurse into the block.
1387 Block& block = static_cast<Block&>(*stmt);
1388
John Stiles8f2a0cf2020-10-13 12:48:21 -04001389 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001390 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001391 for (std::unique_ptr<Statement>& stmt : block.children()) {
1392 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001393 }
John Stiles92219b42020-06-15 12:32:24 -04001394
1395 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001396 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001397 break;
John Stiles92219b42020-06-15 12:32:24 -04001398 }
1399
Ethan Nicholase6592142020-09-08 10:22:09 -04001400 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001401 // Do not append a break to the target.
1402 break;
1403
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001404 default:
John Stiles92219b42020-06-15 12:32:24 -04001405 // Append normal statements to the target.
1406 target->push_back(std::move(stmt));
1407 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001408 }
1409}
1410
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001411// Returns a block containing all of the statements that will be run if the given case matches
1412// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1413// broken by this call and must then be discarded).
1414// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1415// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001416static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1417 SwitchCase* caseToCapture) {
1418 // We have to be careful to not move any of the pointers until after we're sure we're going to
1419 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1420 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001421 auto iter = switchStatement->cases().begin();
1422 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001423 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001424 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001425 }
John Stiles92219b42020-06-15 12:32:24 -04001426 }
1427
1428 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1429 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1430 // statements that we can use for simplification.
1431 auto startIter = iter;
1432 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001433 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001434 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001435 if (contains_conditional_break(*stmt)) {
1436 // We can't reduce switch-cases to a block when they have conditional breaks.
1437 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001438 }
John Stiles92219b42020-06-15 12:32:24 -04001439
1440 if (contains_unconditional_break(*stmt)) {
1441 // We found an unconditional break. We can use this block, but we need to strip
1442 // out the break statement.
1443 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001444 break;
1445 }
1446 }
John Stiles92219b42020-06-15 12:32:24 -04001447
1448 if (unconditionalBreakStmt != nullptr) {
1449 break;
1450 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001451 }
John Stiles92219b42020-06-15 12:32:24 -04001452
1453 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1454 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001455 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001456
1457 // We can move over most of the statements as-is.
1458 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001459 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001460 caseStmts.push_back(std::move(stmt));
1461 }
1462 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001463 }
John Stiles92219b42020-06-15 12:32:24 -04001464
1465 // If we found an unconditional break at the end, we need to move what we can while avoiding
1466 // that break.
1467 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001468 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001469 if (stmt.get() == unconditionalBreakStmt) {
1470 move_all_but_break(stmt, &caseStmts);
1471 unconditionalBreakStmt = nullptr;
1472 break;
1473 }
1474
1475 caseStmts.push_back(std::move(stmt));
1476 }
1477 }
1478
1479 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1480
1481 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001482 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001483}
1484
Ethan Nicholascb670962017-04-20 19:31:52 -04001485void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001486 BasicBlock& b,
1487 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001488 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001489 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001490 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001491 switch (stmt->kind()) {
1492 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001493 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001494 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001495 (!varDecl.value() ||
1496 !varDecl.value()->hasSideEffects())) {
1497 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001498 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001499 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001500 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001501 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001502 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001503 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001504 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001505 }
1506 break;
1507 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001508 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001509 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001510 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001511 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001512 if (i.test()->as<BoolLiteral>().value()) {
1513 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001514 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001515 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001516 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001517 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001518 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001519 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001520 }
1521 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001522 optimizationContext->fUpdated = true;
1523 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001524 break;
1525 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001526 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001527 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001528 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001529 optimizationContext->fUpdated = true;
1530 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001531 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001532 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001533 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001534 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001535 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001536 (*iter)->setStatement(
1537 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001538 } else {
1539 // no if, no else, no test side effects, kill the whole if
1540 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001541 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001542 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001543 optimizationContext->fUpdated = true;
1544 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001545 }
1546 break;
1547 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001548 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001549 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001550 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001551 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001552 // switch is constant, replace it with the case that matches
1553 bool found = false;
1554 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001555 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1556 if (!c->value()) {
1557 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001558 continue;
1559 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001560 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001561 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001562 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001563 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001564 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001565 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001566 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001567 break;
1568 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001569 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1570 optimizationContext->fSilences.find(&s) ==
1571 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001572 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001573 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001574 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001575 }
1576 return; // can't simplify
1577 }
1578 }
1579 }
1580 if (!found) {
1581 // no matching case. use default if it exists, or kill the whole thing
1582 if (defaultCase) {
1583 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1584 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001585 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001586 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001587 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1588 optimizationContext->fSilences.find(&s) ==
1589 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001590 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001591 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001592 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001593 }
1594 return; // can't simplify
1595 }
1596 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001597 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001598 }
1599 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001600 optimizationContext->fUpdated = true;
1601 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001602 }
1603 break;
1604 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001605 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001606 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001607 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001608 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001609 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001610 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001611 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001612 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001613 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001614 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001615 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001616 }
1617 break;
1618 }
1619 default:
1620 break;
1621 }
1622}
1623
Brian Osman010ce6a2020-10-19 16:34:10 -04001624bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001625 bool madeChanges = false;
1626
Ethan Nicholascb670962017-04-20 19:31:52 -04001627 CFG cfg = CFGGenerator().getCFG(f);
1628 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001629
1630 // check for unreachable code
1631 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001632 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001633 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001634 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001635 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001636 if (node.isStatement()) {
1637 offset = (*node.statement())->fOffset;
1638 } else {
1639 offset = (*node.expression())->fOffset;
1640 if ((*node.expression())->is<BoolLiteral>()) {
1641 // Function inlining can generate do { ... } while(false) loops which always
1642 // break, so the boolean condition is considered unreachable. Since not being
1643 // able to reach a literal is a non-issue in the first place, we don't report an
1644 // error in this case.
1645 continue;
1646 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001647 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001648 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001649 }
1650 }
1651 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001652 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001653 }
1654
Ethan Nicholascb670962017-04-20 19:31:52 -04001655 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001656 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001657 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001658 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001659 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001660 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001661 cfg = CFGGenerator().getCFG(f);
1662 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001663 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001664 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001665
John Stiles7d3f0892020-11-03 11:35:01 -05001666 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001667 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001668
1669 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1670 if (eliminatedBlockIds.test(blockId)) {
1671 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1672 optimizationContext.fUpdated = true;
1673 optimizationContext.fNeedsRescan = true;
1674 break;
1675 }
1676
1677 BasicBlock& b = cfg.fBlocks[blockId];
1678 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001679 // Block was reachable before optimization, but has since become unreachable. In
1680 // addition to being dead code, it's broken - since control flow can't reach it, no
1681 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001682 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001683 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001684 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001685 // Eliminating a node runs the risk of eliminating that node's exits as
1686 // well. Keep track of this and do a rescan if we are about to access one
1687 // of these.
1688 for (BlockId id : b.fExits) {
1689 eliminatedBlockIds.set(id);
1690 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001691 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001692 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001693 }
1694 }
1695 continue;
1696 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001697 DefinitionMap definitions = b.fBefore;
1698
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001699 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1700 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001701 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001702 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001703 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001704 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001705 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001706 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001707 break;
1708 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001709 this->addDefinitions(*iter, &definitions);
1710 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001711
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001712 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001713 break;
1714 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001715 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001716 madeChanges |= optimizationContext.fUpdated;
1717 } while (optimizationContext.fUpdated);
1718 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001719
Ethan Nicholas91a10532017-06-22 11:24:38 -04001720 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001721 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001722 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1723 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001724 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001725 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001726 switch (s.kind()) {
1727 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001728 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001729 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001730 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001731 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001732 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001733 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001734 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001735 if (s.as<SwitchStatement>().isStatic() &&
1736 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1737 optimizationContext.fSilences.find(&s) ==
1738 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001739 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001740 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001741 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001742 break;
1743 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001744 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001745 break;
1746 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001747 } else {
1748 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001749 }
1750 }
1751 }
1752
ethannicholas22f939e2016-10-13 13:25:34 -07001753 // check for missing return
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001754 if (f.declaration().returnType() != *fContext->fVoid_Type) {
John Stiles61e75e32020-10-01 15:42:37 -04001755 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001756 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001757 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001758 }
1759 }
John Stiles0cc193a2020-09-09 09:39:34 -04001760
1761 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001762}
1763
Brian Osman32d53552020-09-23 13:55:20 -04001764std::unique_ptr<Program> Compiler::convertProgram(
1765 Program::Kind kind,
1766 String text,
1767 const Program::Settings& settings,
1768 const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
1769 SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001770
Brian Osman0006ad02020-11-18 15:38:39 -05001771 // Loading and optimizing our base module might reset the inliner, so do that first,
1772 // *then* configure the inliner with the settings for this program.
1773 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1774
ethannicholasb3058bd2016-07-01 08:22:01 -07001775 fErrorText = "";
1776 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001777 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001778
1779 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001780 std::unique_ptr<String> textPtr(new String(std::move(text)));
1781 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001782
John Stiles5c7bb322020-10-22 11:09:15 -04001783 // Enable node pooling while converting and optimizing the program for a performance boost.
1784 // The Program will take ownership of the pool.
John Stiles2d68ea32020-10-22 15:42:27 -04001785 std::unique_ptr<Pool> pool = Pool::Create();
1786 pool->attachToThread();
Brian Osman0006ad02020-11-18 15:38:39 -05001787 IRGenerator::IRBundle ir =
1788 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
1789 textPtr->c_str(), textPtr->size(), externalValues);
John Stiles5c7bb322020-10-22 11:09:15 -04001790 auto program = std::make_unique<Program>(kind,
1791 std::move(textPtr),
1792 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001793 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001794 fContext,
1795 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001796 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001797 std::move(ir.fModifiers),
1798 std::move(ir.fSymbolTable),
1799 std::move(pool),
1800 ir.fInputs);
1801 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001802 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001803 // Do not return programs that failed to compile.
1804 } else if (settings.fOptimize && !this->optimize(*program)) {
1805 // Do not return programs that failed to optimize.
1806 } else {
1807 // We have a successful program!
1808 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001809 }
John Stiles5c7bb322020-10-22 11:09:15 -04001810
1811 program->fPool->detachFromThread();
1812 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001813}
1814
Brian Osman0006ad02020-11-18 15:38:39 -05001815bool Compiler::optimize(LoadedModule& module) {
1816 SkASSERT(!fErrorCount);
1817 Program::Settings settings;
1818 fIRGenerator->fKind = module.fKind;
1819 fIRGenerator->fSettings = &settings;
1820 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1821
1822 fInliner.reset(fModifiers.back().get(), &settings);
1823
1824 while (fErrorCount == 0) {
1825 bool madeChanges = false;
1826
1827 // Scan and optimize based on the control-flow graph for each function.
1828 for (const auto& element : module.fElements) {
1829 if (element->is<FunctionDefinition>()) {
1830 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1831 }
1832 }
1833
1834 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001835 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001836
1837 if (!madeChanges) {
1838 break;
1839 }
1840 }
1841 return fErrorCount == 0;
1842}
1843
Ethan Nicholas00543112018-07-31 09:44:36 -04001844bool Compiler::optimize(Program& program) {
1845 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001846 fIRGenerator->fKind = program.fKind;
1847 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001848 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001849
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001850 while (fErrorCount == 0) {
1851 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001852
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001853 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001854 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001855 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001856 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001857 }
1858 }
1859
1860 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001861 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001862
1863 // Remove dead functions. We wait until after analysis so that we still report errors,
1864 // even in unused code.
1865 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001866 auto isDeadFunction = [&](const ProgramElement* element) {
1867 if (!element->is<FunctionDefinition>()) {
1868 return false;
1869 }
1870 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1871 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1872 usage->remove(*element);
1873 madeChanges = true;
1874 return true;
1875 }
1876 return false;
1877 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001878 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001879 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001880 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001881 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001882 }),
1883 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001884 program.fSharedElements.erase(
1885 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1886 isDeadFunction),
1887 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001888 }
1889
1890 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001891 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001892 auto isDeadVariable = [&](const ProgramElement* element) {
1893 if (!element->is<GlobalVarDeclaration>()) {
1894 return false;
1895 }
1896 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1897 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1898 if (usage->isDead(varDecl.var())) {
1899 madeChanges = true;
1900 return true;
1901 }
1902 return false;
1903 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001904 program.fElements.erase(
1905 std::remove_if(program.fElements.begin(), program.fElements.end(),
1906 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001907 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001908 }),
1909 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001910 program.fSharedElements.erase(
1911 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1912 isDeadVariable),
1913 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001914 }
John Stiles73a6bff2020-09-09 13:40:37 -04001915
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001916 if (!madeChanges) {
1917 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001918 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001919 }
1920 return fErrorCount == 0;
1921}
1922
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001923#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1924
Ethan Nicholas00543112018-07-31 09:44:36 -04001925bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001926#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001927 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001928 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001929 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001930 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001931 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001932 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001933 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001934 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001935 String errors;
1936 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1937 const char* m) {
1938 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001939 };
1940 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001941
1942 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1943 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1944 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1945 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1946
1947 if (!result) {
1948#if defined(SKSL_STANDALONE)
1949 // Convert the string-stream to a SPIR-V disassembly.
1950 std::string disassembly;
1951 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1952 errors.append(disassembly);
1953 }
1954 this->error(-1, errors);
1955#else
1956 SkDEBUGFAILF("%s", errors.c_str());
1957#endif
1958 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001959 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001960 }
1961#else
Brian Osman88cda172020-10-09 12:05:16 -04001962 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001963 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001964 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001965#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001966 return result;
1967}
1968
Ethan Nicholas00543112018-07-31 09:44:36 -04001969bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001970 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001971 bool result = this->toSPIRV(program, buffer);
1972 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001973 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001974 }
1975 return result;
1976}
1977
Ethan Nicholas00543112018-07-31 09:44:36 -04001978bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001979 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001980 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001981 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001982 return result;
1983}
1984
Ethan Nicholas00543112018-07-31 09:44:36 -04001985bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001986 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001987 bool result = this->toGLSL(program, buffer);
1988 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001989 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001990 }
1991 return result;
1992}
1993
Brian Osmanc0243912020-02-19 15:35:26 -05001994bool Compiler::toHLSL(Program& program, String* out) {
1995 String spirv;
1996 if (!this->toSPIRV(program, &spirv)) {
1997 return false;
1998 }
1999
2000 return SPIRVtoHLSL(spirv, out);
2001}
2002
Ethan Nicholas00543112018-07-31 09:44:36 -04002003bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002004 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04002005 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04002006 return result;
2007}
2008
Ethan Nicholas00543112018-07-31 09:44:36 -04002009bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04002010 StringStream buffer;
2011 bool result = this->toMetal(program, buffer);
2012 if (result) {
2013 *out = buffer.str();
2014 }
2015 return result;
2016}
2017
Greg Daniela28ea672020-09-25 11:12:56 -04002018#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002019bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002020 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002021 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002022 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04002023 return result;
2024}
2025
Ethan Nicholas00543112018-07-31 09:44:36 -04002026bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002027 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002028 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002029 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002030 return result;
2031}
Greg Daniela28ea672020-09-25 11:12:56 -04002032#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002033
Ethan Nicholas2a479a52020-08-18 16:29:45 -04002034#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04002035
2036#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04002037bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04002038 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04002039 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05002040 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04002041 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002042 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05002043 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04002044 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04002045 return result;
2046}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04002047#endif
2048
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002049std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Brian Osman88cda172020-10-09 12:05:16 -04002050 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002051 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04002052 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
2053 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04002054 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002055 return result;
2056 }
2057 return nullptr;
2058}
2059
Brian Osman401a0092020-09-10 14:47:24 -04002060const char* Compiler::OperatorName(Token::Kind op) {
2061 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002062 case Token::Kind::TK_PLUS: return "+";
2063 case Token::Kind::TK_MINUS: return "-";
2064 case Token::Kind::TK_STAR: return "*";
2065 case Token::Kind::TK_SLASH: return "/";
2066 case Token::Kind::TK_PERCENT: return "%";
2067 case Token::Kind::TK_SHL: return "<<";
2068 case Token::Kind::TK_SHR: return ">>";
2069 case Token::Kind::TK_LOGICALNOT: return "!";
2070 case Token::Kind::TK_LOGICALAND: return "&&";
2071 case Token::Kind::TK_LOGICALOR: return "||";
2072 case Token::Kind::TK_LOGICALXOR: return "^^";
2073 case Token::Kind::TK_BITWISENOT: return "~";
2074 case Token::Kind::TK_BITWISEAND: return "&";
2075 case Token::Kind::TK_BITWISEOR: return "|";
2076 case Token::Kind::TK_BITWISEXOR: return "^";
2077 case Token::Kind::TK_EQ: return "=";
2078 case Token::Kind::TK_EQEQ: return "==";
2079 case Token::Kind::TK_NEQ: return "!=";
2080 case Token::Kind::TK_LT: return "<";
2081 case Token::Kind::TK_GT: return ">";
2082 case Token::Kind::TK_LTEQ: return "<=";
2083 case Token::Kind::TK_GTEQ: return ">=";
2084 case Token::Kind::TK_PLUSEQ: return "+=";
2085 case Token::Kind::TK_MINUSEQ: return "-=";
2086 case Token::Kind::TK_STAREQ: return "*=";
2087 case Token::Kind::TK_SLASHEQ: return "/=";
2088 case Token::Kind::TK_PERCENTEQ: return "%=";
2089 case Token::Kind::TK_SHLEQ: return "<<=";
2090 case Token::Kind::TK_SHREQ: return ">>=";
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002091 case Token::Kind::TK_BITWISEANDEQ: return "&=";
2092 case Token::Kind::TK_BITWISEOREQ: return "|=";
2093 case Token::Kind::TK_BITWISEXOREQ: return "^=";
2094 case Token::Kind::TK_PLUSPLUS: return "++";
2095 case Token::Kind::TK_MINUSMINUS: return "--";
2096 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002097 default:
Brian Osman401a0092020-09-10 14:47:24 -04002098 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002099 }
2100}
2101
2102
2103bool Compiler::IsAssignment(Token::Kind op) {
2104 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002105 case Token::Kind::TK_EQ: // fall through
2106 case Token::Kind::TK_PLUSEQ: // fall through
2107 case Token::Kind::TK_MINUSEQ: // fall through
2108 case Token::Kind::TK_STAREQ: // fall through
2109 case Token::Kind::TK_SLASHEQ: // fall through
2110 case Token::Kind::TK_PERCENTEQ: // fall through
2111 case Token::Kind::TK_SHLEQ: // fall through
2112 case Token::Kind::TK_SHREQ: // fall through
2113 case Token::Kind::TK_BITWISEOREQ: // fall through
2114 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05002115 case Token::Kind::TK_BITWISEANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002116 return true;
2117 default:
2118 return false;
2119 }
2120}
2121
Brian Osman401a0092020-09-10 14:47:24 -04002122Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
2123 switch (op) {
2124 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
2125 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
2126 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
2127 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
2128 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
2129 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
2130 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
2131 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
2132 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
2133 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
Brian Osman401a0092020-09-10 14:47:24 -04002134 default: return op;
2135 }
2136}
2137
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002138Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05002139 if (fSource && offset >= 0) {
2140 int line = 1;
2141 int column = 1;
2142 for (int i = 0; i < offset; i++) {
2143 if ((*fSource)[i] == '\n') {
2144 ++line;
2145 column = 1;
2146 }
2147 else {
2148 ++column;
2149 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002150 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05002151 return Position(line, column);
2152 } else {
2153 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002154 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002155}
2156
2157void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002158 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002159 Position pos = this->position(offset);
Ethan Nicholas3c729892020-12-07 12:47:17 -05002160 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07002161}
2162
Ethan Nicholasdcd2f862020-12-17 23:24:25 +00002163String Compiler::errorText() {
2164 this->writeErrorCount();
Ethan Nicholas00543112018-07-31 09:44:36 -04002165 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002166 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07002167 return result;
2168}
2169
2170void Compiler::writeErrorCount() {
2171 if (fErrorCount) {
2172 fErrorText += to_string(fErrorCount) + " error";
2173 if (fErrorCount > 1) {
2174 fErrorText += "s";
2175 }
2176 fErrorText += "\n";
2177 }
2178}
2179
John Stilesa6841be2020-08-06 14:11:56 -04002180} // namespace SkSL