blob: 9e7e7dec2186c27ab5a260bd6fc9f2b367376863 [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/SkSLCFGGenerator.h"
15#include "src/sksl/SkSLCPPCodeGenerator.h"
16#include "src/sksl/SkSLGLSLCodeGenerator.h"
17#include "src/sksl/SkSLHCodeGenerator.h"
18#include "src/sksl/SkSLIRGenerator.h"
19#include "src/sksl/SkSLMetalCodeGenerator.h"
20#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040021#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050023#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/sksl/ir/SkSLEnum.h"
25#include "src/sksl/ir/SkSLExpression.h"
26#include "src/sksl/ir/SkSLExpressionStatement.h"
27#include "src/sksl/ir/SkSLFunctionCall.h"
28#include "src/sksl/ir/SkSLIntLiteral.h"
29#include "src/sksl/ir/SkSLModifiersDeclaration.h"
30#include "src/sksl/ir/SkSLNop.h"
31#include "src/sksl/ir/SkSLSymbolTable.h"
32#include "src/sksl/ir/SkSLTernaryExpression.h"
33#include "src/sksl/ir/SkSLUnresolvedFunction.h"
34#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040035#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070036
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040037#include <fstream>
38
Ethan Nicholasa11035b2019-11-26 16:27:47 -050039#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
40#include "include/gpu/GrContextOptions.h"
41#include "src/gpu/GrShaderCaps.h"
42#endif
43
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040044#ifdef SK_ENABLE_SPIRV_VALIDATION
45#include "spirv-tools/libspirv.hpp"
46#endif
47
Brian Osman3d87e9f2020-10-08 11:50:22 -040048#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040049
Brian Osman3d87e9f2020-10-08 11:50:22 -040050// In standalone mode, we load the textual sksl source files. GN generates or copies these files
51// to the skslc executable directory. The "data" in this mode is just the filename.
52#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
53
54#else
55
56// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040057#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
58#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
59#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
60#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050061#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050062#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040063#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
64
Brian Osman3d87e9f2020-10-08 11:50:22 -040065#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
66 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040067
68#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040069
ethannicholasb3058bd2016-07-01 08:22:01 -070070namespace SkSL {
71
Brian Osman88cda172020-10-09 12:05:16 -040072class AutoSource {
73public:
74 AutoSource(Compiler* compiler, const String* source)
75 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
76 fCompiler->fSource = source;
77 }
78
79 ~AutoSource() { fCompiler->fSource = fOldSource; }
80
81 Compiler* fCompiler;
82 const String* fOldSource;
83};
84
Brian Osmand7e76592020-11-02 12:26:22 -050085Compiler::Compiler(const ShaderCapsClass* caps, Flags flags)
John Stilesb30151e2021-01-11 16:13:08 -050086 : fContext(std::make_shared<Context>(/*errors=*/*this))
Brian Osman0006ad02020-11-18 15:38:39 -050087 , fCaps(caps)
John Stiles7b920442020-12-17 10:43:41 -050088 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -050089 , fFlags(flags)
90 , fErrorCount(0) {
91 SkASSERT(fCaps);
John Stiles7c3515b2020-10-16 18:38:39 -040092 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050093 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesb30151e2021-01-11 16:13:08 -050094 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), fCaps);
ethannicholasb3058bd2016-07-01 08:22:01 -070095
John Stiles54e7c052021-01-11 14:22:36 -050096#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -070097
Brian Osmanb06301e2020-11-06 11:45:36 -050098 const SkSL::Symbol* rootTypes[] = {
99 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500100
Brian Osmanb06301e2020-11-06 11:45:36 -0500101 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
102 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
103 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500104 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500105
Brian Osmanc0f2b642020-12-22 13:35:55 -0500106 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500107 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500108
Brian Osmanc63f4312020-12-23 11:44:14 -0500109 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700110
Brian Osman20fad322020-12-23 12:42:33 -0500111 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
112 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500113
114 TYPE(FragmentProcessor),
115 };
116
117 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500118 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
119 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
120 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
121 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
122 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
123
124 TYPE(GenUType), TYPE(UVec),
125 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
126
Brian Osmanc0f2b642020-12-22 13:35:55 -0500127 TYPE(Float2x3), TYPE(Float2x4),
128 TYPE(Float3x2), TYPE(Float3x4),
129 TYPE(Float4x2), TYPE(Float4x3),
130
Brian Osmanc63f4312020-12-23 11:44:14 -0500131 TYPE(Half2x3), TYPE(Half2x4),
132 TYPE(Half3x2), TYPE(Half3x4),
133 TYPE(Half4x2), TYPE(Half4x3),
134
Brian Osmanc0f2b642020-12-22 13:35:55 -0500135 TYPE(Mat), TYPE(HMat),
136
Brian Osmanb06301e2020-11-06 11:45:36 -0500137 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
138 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500139 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500140
141 TYPE(ISampler2D),
142 TYPE(Image2D), TYPE(IImage2D),
143 TYPE(SubpassInput), TYPE(SubpassInputMS),
144
Brian Osmanb06301e2020-11-06 11:45:36 -0500145 TYPE(Sampler),
146 TYPE(Texture2D),
147 };
148
149 for (const SkSL::Symbol* type : rootTypes) {
150 fRootSymbolTable->addWithoutOwnership(type);
151 }
152 for (const SkSL::Symbol* type : privateTypes) {
153 fPrivateSymbolTable->addWithoutOwnership(type);
154 }
155
156#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700157
Brian Osman3887a012020-09-30 13:22:27 -0400158 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
159 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500160 fPrivateSymbolTable->add(
161 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500162 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500163 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500164 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500165 /*builtin=*/false,
166 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500167
Brian Osman3d87e9f2020-10-08 11:50:22 -0400168 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500169 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700170}
171
John Stilesdd13dba2020-10-29 10:45:34 -0400172Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700173
Brian Osman56269982020-11-20 12:38:07 -0500174const ParsedModule& Compiler::loadGPUModule() {
175 if (!fGPUModule.fSymbols) {
176 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
177 }
178 return fGPUModule;
179}
180
181const ParsedModule& Compiler::loadFragmentModule() {
182 if (!fFragmentModule.fSymbols) {
183 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag),
184 this->loadGPUModule());
185 }
186 return fFragmentModule;
187}
188
189const ParsedModule& Compiler::loadVertexModule() {
190 if (!fVertexModule.fSymbols) {
191 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert),
192 this->loadGPUModule());
193 }
194 return fVertexModule;
195}
196
Brian Osman88cda172020-10-09 12:05:16 -0400197const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400198 if (!fGeometryModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500199 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom),
200 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400201 }
Brian Osman88cda172020-10-09 12:05:16 -0400202 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400203}
204
Brian Osman88cda172020-10-09 12:05:16 -0400205const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400206 if (!fFPModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500207 fFPModule = this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp),
208 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400209 }
Brian Osman88cda172020-10-09 12:05:16 -0400210 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400211}
212
Brian Osmanb06301e2020-11-06 11:45:36 -0500213const ParsedModule& Compiler::loadPublicModule() {
214 if (!fPublicModule.fSymbols) {
215 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
216 }
217 return fPublicModule;
218}
219
Brian Osman91946752020-12-21 13:20:40 -0500220const ParsedModule& Compiler::loadRuntimeEffectModule() {
221 if (!fRuntimeEffectModule.fSymbols) {
222 fRuntimeEffectModule = this->parseModule(Program::kRuntimeEffect_Kind, MODULE_DATA(runtime),
223 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400224
Brian Osman91946752020-12-21 13:20:40 -0500225 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500226 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400227
John Stiles54e7c052021-01-11 14:22:36 -0500228 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
229 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
230 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400231
John Stiles54e7c052021-01-11 14:22:36 -0500232 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
233 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
234 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400235
John Stiles54e7c052021-01-11 14:22:36 -0500236 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
237 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
238 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400239
John Stiles54e7c052021-01-11 14:22:36 -0500240 fRuntimeEffectModule.fSymbols->addAlias("mat2x2", fContext->fTypes.fFloat2x2.get());
241 fRuntimeEffectModule.fSymbols->addAlias("mat2x3", fContext->fTypes.fFloat2x3.get());
242 fRuntimeEffectModule.fSymbols->addAlias("mat2x4", fContext->fTypes.fFloat2x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400243
John Stiles54e7c052021-01-11 14:22:36 -0500244 fRuntimeEffectModule.fSymbols->addAlias("mat3x2", fContext->fTypes.fFloat3x2.get());
245 fRuntimeEffectModule.fSymbols->addAlias("mat3x3", fContext->fTypes.fFloat3x3.get());
246 fRuntimeEffectModule.fSymbols->addAlias("mat3x4", fContext->fTypes.fFloat3x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400247
John Stiles54e7c052021-01-11 14:22:36 -0500248 fRuntimeEffectModule.fSymbols->addAlias("mat4x2", fContext->fTypes.fFloat4x2.get());
249 fRuntimeEffectModule.fSymbols->addAlias("mat4x3", fContext->fTypes.fFloat4x3.get());
250 fRuntimeEffectModule.fSymbols->addAlias("mat4x4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400251 }
Brian Osman91946752020-12-21 13:20:40 -0500252 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400253}
254
Brian Osman88cda172020-10-09 12:05:16 -0400255const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
256 switch (kind) {
Brian Osman91946752020-12-21 13:20:40 -0500257 case Program::kVertex_Kind: return this->loadVertexModule(); break;
258 case Program::kFragment_Kind: return this->loadFragmentModule(); break;
259 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
260 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
261 case Program::kRuntimeEffect_Kind: return this->loadRuntimeEffectModule(); break;
Brian Osmance750362021-01-21 16:33:06 -0500262 case Program::kGeneric_Kind: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400263 }
264 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400265}
266
Brian Osman3d87e9f2020-10-08 11:50:22 -0400267LoadedModule Compiler::loadModule(Program::Kind kind,
268 ModuleData data,
269 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400270 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500271 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
272 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
273 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
274 // like samplers or textures. Today, 'Private' does contain the union of all known types,
275 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
276 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
277 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400278 }
279
280#if defined(SKSL_STANDALONE)
281 SkASSERT(data.fPath);
282 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400283 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
284 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400285 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400286 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400287 abort();
288 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400289 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400290 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400291 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400292 SkASSERT(fIRGenerator->fCanInline);
293 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400294 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500295 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500296 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500297 /*isBuiltinCode=*/true, source->c_str(), source->length(),
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500298 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400299 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500300 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400301 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400302 if (this->fErrorCount) {
303 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400304 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400305 }
Brian Osman88cda172020-10-09 12:05:16 -0400306 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400307#else
308 SkASSERT(data.fData && (data.fSize != 0));
309 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
310 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500311 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400312 fModifiers.push_back(fIRGenerator->releaseModifiers());
313#endif
314
315 return module;
316}
317
318ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500319 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
320 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400321
322 // For modules that just declare (but don't define) intrinsic functions, there will be no new
323 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500324 if (module.fElements.empty()) {
325 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400326 }
327
328 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
329
330 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
331 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500332 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400333 switch (element->kind()) {
334 case ProgramElement::Kind::kFunction: {
335 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400336 SkASSERT(f.declaration().isBuiltin());
337 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400338 break;
339 }
John Stiles569249b2020-11-03 12:18:22 -0500340 case ProgramElement::Kind::kFunctionPrototype: {
341 // These are already in the symbol table.
342 break;
343 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400344 case ProgramElement::Kind::kEnum: {
345 const Enum& e = element->as<Enum>();
346 SkASSERT(e.isBuiltin());
347 intrinsics->insertOrDie(e.typeName(), std::move(element));
348 break;
349 }
350 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400351 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
352 const Variable& var = global.declaration()->as<VarDeclaration>().var();
353 SkASSERT(var.isBuiltin());
354 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400355 break;
356 }
357 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400358 const Variable& var = element->as<InterfaceBlock>().variable();
359 SkASSERT(var.isBuiltin());
360 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400361 break;
362 }
363 default:
364 printf("Unsupported element: %s\n", element->description().c_str());
365 SkASSERT(false);
366 break;
367 }
368 }
369
Brian Osman0006ad02020-11-18 15:38:39 -0500370 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400371}
372
ethannicholas22f939e2016-10-13 13:25:34 -0700373// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500374void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
375 DefinitionMap* definitions) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400376 switch (lvalue->kind()) {
377 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -0400378 const Variable& var = *lvalue->as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400379 if (var.storage() == Variable::Storage::kLocal) {
John Stiles796cdb72020-10-08 12:06:53 -0400380 definitions->set(&var, expr);
ethannicholas22f939e2016-10-13 13:25:34 -0700381 }
382 break;
383 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400384 case Expression::Kind::kSwizzle:
ethannicholas22f939e2016-10-13 13:25:34 -0700385 // We consider the variable written to as long as at least some of its components have
386 // been written to. This will lead to some false negatives (we won't catch it if you
387 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400388 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
389 // 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 -0700390 // more complicated whole-program analysis. This is probably good enough.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400391 this->addDefinition(lvalue->as<Swizzle>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400392 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700393 definitions);
394 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400395 case Expression::Kind::kIndex:
ethannicholas22f939e2016-10-13 13:25:34 -0700396 // see comments in Swizzle
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400397 this->addDefinition(lvalue->as<IndexExpression>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400398 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700399 definitions);
400 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400401 case Expression::Kind::kFieldAccess:
ethannicholas22f939e2016-10-13 13:25:34 -0700402 // see comments in Swizzle
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400403 this->addDefinition(lvalue->as<FieldAccess>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400404 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700405 definitions);
406 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400407 case Expression::Kind::kTernary:
Ethan Nicholasa583b812018-01-18 13:32:11 -0500408 // To simplify analysis, we just pretend that we write to both sides of the ternary.
409 // This allows for false positives (meaning we fail to detect that a variable might not
410 // have been assigned), but is preferable to false negatives.
Ethan Nicholasdd218162020-10-08 05:48:01 -0400411 this->addDefinition(lvalue->as<TernaryExpression>().ifTrue().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400412 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500413 definitions);
Ethan Nicholasdd218162020-10-08 05:48:01 -0400414 this->addDefinition(lvalue->as<TernaryExpression>().ifFalse().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400415 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500416 definitions);
417 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700418 default:
419 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400420 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700421 }
422}
423
424// add local variables defined by this node to the set
John Stiles796cdb72020-10-08 12:06:53 -0400425void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) {
John Stiles70025e52020-09-28 16:08:58 -0400426 if (node.isExpression()) {
427 Expression* expr = node.expression()->get();
428 switch (expr->kind()) {
429 case Expression::Kind::kBinary: {
430 BinaryExpression* b = &expr->as<BinaryExpression>();
431 if (b->getOperator() == Token::Kind::TK_EQ) {
John Stiles2d4f9592020-10-30 10:29:12 -0400432 this->addDefinition(b->left().get(), &b->right(), definitions);
John Stiles70025e52020-09-28 16:08:58 -0400433 } else if (Compiler::IsAssignment(b->getOperator())) {
434 this->addDefinition(
John Stiles2d4f9592020-10-30 10:29:12 -0400435 b->left().get(),
John Stiles70025e52020-09-28 16:08:58 -0400436 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
437 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500438
ethannicholas22f939e2016-10-13 13:25:34 -0700439 }
John Stiles70025e52020-09-28 16:08:58 -0400440 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700441 }
John Stiles70025e52020-09-28 16:08:58 -0400442 case Expression::Kind::kFunctionCall: {
443 const FunctionCall& c = expr->as<FunctionCall>();
Brian Osman5bf3e202020-10-13 10:34:18 -0400444 const std::vector<const Variable*>& parameters = c.function().parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400445 for (size_t i = 0; i < parameters.size(); ++i) {
446 if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stiles70025e52020-09-28 16:08:58 -0400447 this->addDefinition(
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400448 c.arguments()[i].get(),
John Stiles70025e52020-09-28 16:08:58 -0400449 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
450 definitions);
451 }
452 }
453 break;
454 }
455 case Expression::Kind::kPrefix: {
456 const PrefixExpression* p = &expr->as<PrefixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400457 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
458 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400459 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400460 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400461 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
462 definitions);
463 }
464 break;
465 }
466 case Expression::Kind::kPostfix: {
467 const PostfixExpression* p = &expr->as<PostfixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400468 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
469 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400470 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400471 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400472 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
473 definitions);
474 }
475 break;
476 }
477 case Expression::Kind::kVariableReference: {
478 const VariableReference* v = &expr->as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400479 if (v->refKind() != VariableReference::RefKind::kRead) {
John Stiles70025e52020-09-28 16:08:58 -0400480 this->addDefinition(
481 v,
482 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
483 definitions);
484 }
485 break;
486 }
487 default:
488 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700489 }
John Stiles70025e52020-09-28 16:08:58 -0400490 } else if (node.isStatement()) {
491 Statement* stmt = node.statement()->get();
492 if (stmt->is<VarDeclaration>()) {
493 VarDeclaration& vd = stmt->as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400494 if (vd.value()) {
495 definitions->set(&vd.var(), &vd.value());
ethannicholas22f939e2016-10-13 13:25:34 -0700496 }
ethannicholas22f939e2016-10-13 13:25:34 -0700497 }
498 }
499}
500
John Stilese6150002020-10-05 12:03:53 -0400501void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700502 BasicBlock& block = cfg->fBlocks[blockId];
503
504 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500505 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700506 for (const BasicBlock::Node& n : block.fNodes) {
507 this->addDefinitions(n, &after);
508 }
509
510 // propagate definitions to exits
511 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400512 if (exitId == blockId) {
513 continue;
514 }
ethannicholas22f939e2016-10-13 13:25:34 -0700515 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500516 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400517 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
518 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400519 // exit has no definition for it, just copy it and reprocess exit block
520 processedSet->reset(exitId);
John Stiles796cdb72020-10-08 12:06:53 -0400521 exit.fBefore[var] = e1;
ethannicholas22f939e2016-10-13 13:25:34 -0700522 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500523 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400524 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700525 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400526 // definition has changed, merge and reprocess the exit block
527 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500528 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400529 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500530 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400531 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500532 }
ethannicholas22f939e2016-10-13 13:25:34 -0700533 }
534 }
John Stiles65b48272020-12-22 17:18:34 -0500535 }
ethannicholas22f939e2016-10-13 13:25:34 -0700536 }
537}
538
539// returns a map which maps all local variables in the function to null, indicating that their value
540// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500541static DefinitionMap compute_start_state(const CFG& cfg) {
542 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400543 for (const auto& block : cfg.fBlocks) {
544 for (const auto& node : block.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -0400545 if (node.isStatement()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400546 const Statement* s = node.statement()->get();
Brian Osmanc0213602020-10-06 14:43:32 -0400547 if (s->is<VarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400548 result[&s->as<VarDeclaration>().var()] = nullptr;
ethannicholas22f939e2016-10-13 13:25:34 -0700549 }
550 }
551 }
552 }
553 return result;
554}
555
Ethan Nicholascb670962017-04-20 19:31:52 -0400556/**
557 * Returns true if assigning to this lvalue has no effect.
558 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400559static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400560 switch (lvalue.kind()) {
561 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400562 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400563 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400564 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400565 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400566 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400567 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400568 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400569 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400570 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400571 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400572 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400573 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400574 return !t.test()->hasSideEffects() &&
575 is_dead(*t.ifTrue(), usage) &&
576 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500577 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400578 default:
John Stileseada7bc2021-02-02 16:29:32 -0500579 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500580 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400581 }
582}
ethannicholas22f939e2016-10-13 13:25:34 -0700583
Ethan Nicholascb670962017-04-20 19:31:52 -0400584/**
585 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
586 * to a dead target and lack of side effects on the left hand side.
587 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400588static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400589 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400590 return false;
591 }
John Stiles2d4f9592020-10-30 10:29:12 -0400592 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400593}
594
595void Compiler::computeDataFlow(CFG* cfg) {
596 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400597
598 // We set bits in the "processed" set after a block has been scanned.
599 SkBitSet processedSet(cfg->fBlocks.size());
600 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
601 processedSet.set(*blockId);
602 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700603 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400604}
605
606/**
607 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
608 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
609 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
610 * need to be regenerated).
611 */
John Stilesafbf8992020-08-18 10:08:21 -0400612static bool try_replace_expression(BasicBlock* b,
613 std::vector<BasicBlock::Node>::iterator* iter,
614 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400615 std::unique_ptr<Expression>* target = (*iter)->expression();
616 if (!b->tryRemoveExpression(iter)) {
617 *target = std::move(*newExpression);
618 return false;
619 }
620 *target = std::move(*newExpression);
621 return b->tryInsertExpression(iter, target);
622}
623
624/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400625 * Returns true if the expression is a constant numeric literal with the specified value, or a
626 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400627 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400628template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400629static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400630 switch (expr.kind()) {
631 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400632 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400633
Ethan Nicholase6592142020-09-08 10:22:09 -0400634 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400635 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400636
Ethan Nicholase6592142020-09-08 10:22:09 -0400637 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400638 const Constructor& constructor = expr.as<Constructor>();
639 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400640 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400641 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400642 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500643 if (constructor.componentType().isFloat()) {
644 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400645 if (constructor.getFVecComponent(i) != value) {
646 return false;
647 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500648 }
649 return true;
650 } else if (constructor.componentType().isInteger()) {
651 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400652 if (constructor.getIVecComponent(i) != value) {
653 return false;
654 }
655 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500656 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400657 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500658 // Other types (e.g. boolean) might occur, but aren't supported here.
659 return false;
John Stiles9d944232020-08-19 09:56:49 -0400660
Ethan Nicholase6592142020-09-08 10:22:09 -0400661 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400662 SkASSERT(constructor.arguments().size() == 1);
663 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400664
665 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400666 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400667 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400668 }
669 return false;
670 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400671 default:
672 return false;
673 }
674}
675
676/**
677 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
678 * and CFG structures).
679 */
John Stilesafbf8992020-08-18 10:08:21 -0400680static void delete_left(BasicBlock* b,
681 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400682 Compiler::OptimizationContext* optimizationContext) {
683 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400684 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400685 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400686 Expression& left = *bin.left();
687 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400688 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400689 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400690 if (bin.getOperator() == Token::Kind::TK_EQ) {
691 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400692 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400693 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400694 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400695 // Remove references within LHS.
696 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400697 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400698 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400699 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400700 return;
701 }
702 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400703 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400704 return;
705 }
706 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400707 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400708 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400709 return;
710 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400711 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400712 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400713}
714
715/**
716 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
717 * CFG structures).
718 */
John Stilesafbf8992020-08-18 10:08:21 -0400719static void delete_right(BasicBlock* b,
720 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400721 Compiler::OptimizationContext* optimizationContext) {
722 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400723 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400724 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400725 std::unique_ptr<Expression>& leftPointer = bin.left();
726 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400727 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400728 // Remove references within RHS.
729 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400730 if (!b->tryRemoveExpressionBefore(iter, &right)) {
731 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400732 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400733 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400734 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400735 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400736 if (*iter == b->fNodes.begin()) {
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);
John Stiles70025e52020-09-28 16:08:58 -0400741 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400742 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400743 return;
744 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400745 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400746 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400747}
748
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400749/**
750 * Constructs the specified type using a single argument.
751 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400752static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400753 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400754 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400755 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400756 return result;
757}
758
759/**
760 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
761 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
762 */
763static void vectorize(BasicBlock* b,
764 std::vector<BasicBlock::Node>::iterator* iter,
765 const Type& type,
766 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400767 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400768 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500769 SkASSERT(type.isVector());
770 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400771 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400772 std::unique_ptr<Expression>* target = (*iter)->expression();
773 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400774 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400775 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400776 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400777 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400778 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400779 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400780 }
781 }
782}
783
784/**
785 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
786 * left to yield vec<n>(x).
787 */
788static void vectorize_left(BasicBlock* b,
789 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400790 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400791 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400792 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400793 optimizationContext->fUsage->remove(bin.right().get());
794 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400795}
796
797/**
798 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
799 * right to yield vec<n>(y).
800 */
801static void vectorize_right(BasicBlock* b,
802 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400803 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400804 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400805 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400806 optimizationContext->fUsage->remove(bin.left().get());
807 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400808}
809
810// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400811static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400812 switch (expr.kind()) {
813 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400814 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400815 break;
816 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400817 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400818 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400819 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400820 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400821 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400822 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400823 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400824 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400825 break;
826 default:
John Stilesf57207b2021-02-02 17:50:34 -0500827 SK_ABORT("shouldn't be writing to this kind of expression\n");
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400828 break;
829 }
830}
831
Ethan Nicholascb670962017-04-20 19:31:52 -0400832void Compiler::simplifyExpression(DefinitionMap& definitions,
833 BasicBlock& b,
834 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400835 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400836 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400837 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500838
Ethan Nicholascb670962017-04-20 19:31:52 -0400839 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400840 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
841 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400842 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400843 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400844 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400845 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400846 // Remove references within 'expr', add references within 'optimized'
847 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400848 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400849 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400850 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400851 }
John Stiles70025e52020-09-28 16:08:58 -0400852 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400853 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400854 }
855 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400856 switch (expr->kind()) {
857 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400858 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400859 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400860 if (ref.refKind() != VariableReference::RefKind::kWrite &&
861 ref.refKind() != VariableReference::RefKind::kPointer &&
862 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400863 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
864 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000865 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400866 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400867 }
868 break;
869 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400870 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400871 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400872 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400873 // ternary has a constant test, replace it with either the true or
874 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400875 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400876 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400877 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400878 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400879 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400880 optimizationContext->fUpdated = true;
881 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400882 }
883 break;
884 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400885 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400886 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400887 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400888 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400889 break;
890 }
John Stiles2d4f9592020-10-30 10:29:12 -0400891 Expression& left = *bin->left();
892 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400893 const Type& leftType = left.type();
894 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400895 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500896 if ((!leftType.isScalar() && !leftType.isVector()) ||
897 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400898 break;
899 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400900 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400901 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400902 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500903 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400904 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400905 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400906 } else {
907 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400908 // 1 * float4(x) -> float4(x)
909 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400910 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400911 }
912 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400913 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500914 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400915 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400916 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400917 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400918 } else {
919 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400920 // float4(0) * x -> float4(0)
921 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400922 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400923 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500924 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400925 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400926 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400927 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500928 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400929 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400930 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400931 } else {
932 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400933 // float4(x) * 1 -> float4(x)
934 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400935 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400936 }
937 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400938 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500939 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400940 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400941 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400942 } else {
943 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400944 // x * float4(0) -> float4(0)
945 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400946 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400947 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500948 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400949 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400950 }
951 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400952 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400953 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500954 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400955 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400956 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400957 } else {
958 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400959 // 0 + float4(x) -> float4(x)
960 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400961 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400962 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400963 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500964 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400965 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400966 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400967 } else {
968 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400969 // float4(x) + 0 -> float4(x)
970 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400971 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400972 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400973 }
974 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400975 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400976 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500977 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400978 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400979 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400980 } else {
981 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400982 // float4(x) - 0 -> float4(x)
983 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400984 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400985 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400986 }
987 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400988 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400989 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500990 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400991 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400992 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400993 } else {
994 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400995 // float4(x) / 1 -> float4(x)
996 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400997 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400998 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400999 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -05001000 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001001 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001002 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001003 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001004 } else {
1005 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001006 // float4(0) / x -> float4(0)
1007 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001008 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001009 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001010 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001011 }
1012 }
1013 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001014 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001015 if (is_constant(right, 0)) {
1016 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001017 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001018 }
1019 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001020 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001021 if (is_constant(right, 0)) {
1022 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001023 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001024 }
1025 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001026 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001027 if (is_constant(right, 1)) {
1028 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001029 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001030 }
1031 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001032 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001033 if (is_constant(right, 1)) {
1034 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001035 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001036 }
1037 break;
1038 default:
1039 break;
1040 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001041 break;
1042 }
John Stilesf5c1d042020-11-21 23:26:07 -05001043 case Expression::Kind::kConstructor: {
1044 // Find constructors embedded inside constructors and flatten them out where possible.
1045 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
1046 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
1047 // Leave single-argument constructors alone, though. These might be casts or splats.
1048 Constructor& c = expr->as<Constructor>();
1049 if (c.type().columns() > 1) {
1050 // Inspect each constructor argument to see if it's a candidate for flattening.
1051 // Remember matched arguments in a bitfield, "argsToOptimize".
1052 int argsToOptimize = 0;
1053 int currBit = 1;
1054 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1055 if (arg->is<Constructor>()) {
1056 Constructor& inner = arg->as<Constructor>();
1057 if (inner.arguments().size() > 1 &&
1058 inner.type().componentType() == c.type().componentType()) {
1059 argsToOptimize |= currBit;
1060 }
1061 }
1062 currBit <<= 1;
1063 }
1064 if (argsToOptimize) {
1065 // We found at least one argument that could be flattened out. Re-walk the
1066 // constructor args and flatten the candidates we found during our initial pass.
1067 ExpressionArray flattened;
1068 flattened.reserve_back(c.type().columns());
1069 currBit = 1;
1070 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1071 if (argsToOptimize & currBit) {
1072 Constructor& inner = arg->as<Constructor>();
1073 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
1074 flattened.push_back(innerArg->clone());
1075 }
1076 } else {
1077 flattened.push_back(arg->clone());
1078 }
1079 currBit <<= 1;
1080 }
1081 auto optimized = std::unique_ptr<Expression>(
1082 new Constructor(c.fOffset, &c.type(), std::move(flattened)));
1083 // No fUsage change; no references have been added or removed anywhere.
1084 optimizationContext->fUpdated = true;
1085 if (!try_replace_expression(&b, iter, &optimized)) {
1086 optimizationContext->fNeedsRescan = true;
1087 return;
1088 }
1089 SkASSERT((*iter)->isExpression());
1090 break;
1091 }
1092 }
1093 break;
1094 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001095 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001096 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -05001097 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001098 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001099 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001100 for (int i = 0; i < (int) s.components().size(); ++i) {
1101 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001102 identity = false;
1103 break;
1104 }
1105 }
1106 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001107 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001108 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001109 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001110 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001111 return;
1112 }
John Stiles70025e52020-09-28 16:08:58 -04001113 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001114 break;
1115 }
1116 }
John Stiles108bbe22020-11-18 11:10:38 -05001117 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1118 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001119 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001120 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001121 for (int c : s.components()) {
1122 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001123 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001124 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001125 final));
John Stilesd2f51b12021-01-07 18:12:31 -05001126 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -05001127 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -05001128 try_replace_expression(&b, iter, &replacement);
1129 optimizationContext->fUpdated = true;
1130 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001131 break;
1132 }
1133 // Optimize swizzles of constructors.
1134 if (s.base()->is<Constructor>()) {
1135 Constructor& base = s.base()->as<Constructor>();
1136 std::unique_ptr<Expression> replacement;
1137 const Type& componentType = base.type().componentType();
1138 int swizzleSize = s.components().size();
1139
1140 // The IR generator has already converted any zero/one swizzle components into
1141 // constructors containing zero/one args. Confirm that this is true by checking that
1142 // our swizzle components are all `xyzw` (values 0 through 3).
1143 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1144 [](int8_t c) { return c >= 0 && c <= 3; }));
1145
John Stiles9aeed132020-11-24 17:36:06 -05001146 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001147 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1148 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001149 const Expression& argument = *base.arguments().front();
1150 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1151 /*rows=*/1);
1152 replacement = Constructor::SimplifyConversion(constructorType, argument);
1153 if (!replacement) {
1154 ExpressionArray newArgs;
1155 newArgs.push_back(argument.clone());
1156 replacement = std::make_unique<Constructor>(base.fOffset, &constructorType,
1157 std::move(newArgs));
1158 }
John Stiles108bbe22020-11-18 11:10:38 -05001159
John Stilesa60ac0c2020-12-22 08:59:51 -05001160 // We're replacing an expression with a cloned version; we'll need a rescan.
1161 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1162 // reference counts.
1163 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001164 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001165 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001166 break;
1167 }
1168
John Stiles0777ac42020-11-19 11:06:47 -05001169 // Swizzles can duplicate some elements and discard others, e.g.
1170 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1171 // - Expressions with side effects need to occur exactly once, even if they
1172 // would otherwise be swizzle-eliminated
1173 // - Non-trivial expressions should not be repeated, but elimination is OK.
1174 //
1175 // Look up the argument for the constructor at each index. This is typically simple
1176 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1177 // seems. This example would result in:
1178 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1179 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1180 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1181 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1182 struct ConstructorArgMap {
1183 int8_t fArgIndex;
1184 int8_t fComponent;
1185 };
1186
1187 int numConstructorArgs = base.type().columns();
1188 ConstructorArgMap argMap[4] = {};
1189 int writeIdx = 0;
1190 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1191 const Expression& expr = *base.arguments()[argIdx];
1192 int argWidth = expr.type().columns();
1193 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1194 argMap[writeIdx].fArgIndex = argIdx;
1195 argMap[writeIdx].fComponent = componentIdx;
1196 ++writeIdx;
1197 }
1198 }
1199 SkASSERT(writeIdx == numConstructorArgs);
1200
1201 // Count up the number of times each constructor argument is used by the
1202 // swizzle.
1203 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1204 // - bar.yz is referenced 3 times, by `.x_xy`
1205 // - half(foo) is referenced 1 time, by `._w__`
1206 int8_t exprUsed[4] = {};
1207 for (int c : s.components()) {
1208 exprUsed[argMap[c].fArgIndex]++;
1209 }
1210
1211 bool safeToOptimize = true;
1212 for (int index = 0; index < numConstructorArgs; ++index) {
1213 int8_t constructorArgIndex = argMap[index].fArgIndex;
1214 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1215
1216 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001217 if (exprUsed[constructorArgIndex] > 1 &&
1218 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001219 safeToOptimize = false;
1220 break;
1221 }
1222 // Check that side-effect-bearing expressions are swizzled in exactly once.
1223 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1224 safeToOptimize = false;
1225 break;
1226 }
1227 }
1228
1229 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001230 struct ReorderedArgument {
1231 int8_t fArgIndex;
1232 ComponentArray fComponents;
1233 };
1234 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001235 for (int c : s.components()) {
1236 const ConstructorArgMap& argument = argMap[c];
1237 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1238
John Stiles9aeed132020-11-24 17:36:06 -05001239 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001240 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001241 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001242 reorderedArgs.push_back({argument.fArgIndex,
1243 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001244 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001245 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001246 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001247 if (reorderedArgs.empty() ||
1248 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1249 // This can't be combined with the previous argument. Add a new one.
1250 reorderedArgs.push_back({argument.fArgIndex,
1251 ComponentArray{argument.fComponent}});
1252 } else {
1253 // Since we know this argument uses components, it should already
1254 // have at least one component set.
1255 SkASSERT(!reorderedArgs.back().fComponents.empty());
1256 // Build up the current argument with one more component.
1257 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1258 }
John Stiles0777ac42020-11-19 11:06:47 -05001259 }
1260 }
John Stilesd9076cb2020-11-19 12:18:36 -05001261
1262 // Convert our reordered argument list to an actual array of expressions, with
1263 // the new order and any new inner swizzles that need to be applied. Note that
1264 // we expect followup passes to clean up the inner swizzles.
1265 ExpressionArray newArgs;
1266 newArgs.reserve_back(swizzleSize);
1267 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1268 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1269 if (reorderedArg.fComponents.empty()) {
1270 newArgs.push_back(baseArg.clone());
1271 } else {
1272 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1273 reorderedArg.fComponents));
1274 }
1275 }
1276
1277 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001278 replacement = std::make_unique<Constructor>(
1279 base.fOffset,
1280 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1281 std::move(newArgs));
1282
John Stilesa60ac0c2020-12-22 08:59:51 -05001283 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001284 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001285
1286 // We're replacing an expression with a cloned version; we'll need a rescan.
1287 try_replace_expression(&b, iter, &replacement);
1288 optimizationContext->fUpdated = true;
1289 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001290 }
John Stiles108bbe22020-11-18 11:10:38 -05001291 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001292 }
John Stiles30212b72020-06-11 17:55:07 -04001293 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001294 }
1295 default:
1296 break;
1297 }
1298}
1299
John Stiles92219b42020-06-15 12:32:24 -04001300// Returns true if this statement could potentially execute a break at the current level. We ignore
1301// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001302static bool contains_conditional_break(Statement& stmt) {
1303 class ContainsConditionalBreak : public ProgramVisitor {
1304 public:
1305 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001306 switch (stmt.kind()) {
1307 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001308 return this->INHERITED::visitStatement(stmt);
1309
Ethan Nicholase6592142020-09-08 10:22:09 -04001310 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001311 return fInConditional > 0;
1312
Ethan Nicholase6592142020-09-08 10:22:09 -04001313 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001314 ++fInConditional;
1315 bool result = this->INHERITED::visitStatement(stmt);
1316 --fInConditional;
1317 return result;
1318 }
1319
1320 default:
1321 return false;
1322 }
1323 }
1324
1325 int fInConditional = 0;
1326 using INHERITED = ProgramVisitor;
1327 };
1328
1329 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001330}
1331
Ethan Nicholas5005a222018-08-24 13:06:27 -04001332// returns true if this statement definitely executes a break at the current level (we ignore
1333// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001334static bool contains_unconditional_break(Statement& stmt) {
1335 class ContainsUnconditionalBreak : public ProgramVisitor {
1336 public:
1337 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001338 switch (stmt.kind()) {
1339 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001340 return this->INHERITED::visitStatement(stmt);
1341
Ethan Nicholase6592142020-09-08 10:22:09 -04001342 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001343 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001344
1345 default:
1346 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001347 }
John Stilesb92641c2020-08-31 18:09:01 -04001348 }
John Stiles92219b42020-06-15 12:32:24 -04001349
John Stilesb92641c2020-08-31 18:09:01 -04001350 using INHERITED = ProgramVisitor;
1351 };
John Stiles92219b42020-06-15 12:32:24 -04001352
John Stilesb92641c2020-08-31 18:09:01 -04001353 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001354}
1355
John Stiles8f2a0cf2020-10-13 12:48:21 -04001356static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001357 switch (stmt->kind()) {
1358 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001359 // Recurse into the block.
1360 Block& block = static_cast<Block&>(*stmt);
1361
John Stiles8f2a0cf2020-10-13 12:48:21 -04001362 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001363 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001364 for (std::unique_ptr<Statement>& stmt : block.children()) {
1365 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001366 }
John Stiles92219b42020-06-15 12:32:24 -04001367
1368 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001369 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001370 break;
John Stiles92219b42020-06-15 12:32:24 -04001371 }
1372
Ethan Nicholase6592142020-09-08 10:22:09 -04001373 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001374 // Do not append a break to the target.
1375 break;
1376
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001377 default:
John Stiles92219b42020-06-15 12:32:24 -04001378 // Append normal statements to the target.
1379 target->push_back(std::move(stmt));
1380 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001381 }
1382}
1383
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001384// Returns a block containing all of the statements that will be run if the given case matches
1385// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1386// broken by this call and must then be discarded).
1387// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1388// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001389static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1390 SwitchCase* caseToCapture) {
1391 // We have to be careful to not move any of the pointers until after we're sure we're going to
1392 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1393 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001394 auto iter = switchStatement->cases().begin();
1395 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001396 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001397 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001398 }
John Stiles92219b42020-06-15 12:32:24 -04001399 }
1400
1401 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1402 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1403 // statements that we can use for simplification.
1404 auto startIter = iter;
1405 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001406 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001407 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001408 if (contains_conditional_break(*stmt)) {
1409 // We can't reduce switch-cases to a block when they have conditional breaks.
1410 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001411 }
John Stiles92219b42020-06-15 12:32:24 -04001412
1413 if (contains_unconditional_break(*stmt)) {
1414 // We found an unconditional break. We can use this block, but we need to strip
1415 // out the break statement.
1416 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001417 break;
1418 }
1419 }
John Stiles92219b42020-06-15 12:32:24 -04001420
1421 if (unconditionalBreakStmt != nullptr) {
1422 break;
1423 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001424 }
John Stiles92219b42020-06-15 12:32:24 -04001425
1426 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1427 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001428 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001429
1430 // We can move over most of the statements as-is.
1431 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001432 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001433 caseStmts.push_back(std::move(stmt));
1434 }
1435 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001436 }
John Stiles92219b42020-06-15 12:32:24 -04001437
1438 // If we found an unconditional break at the end, we need to move what we can while avoiding
1439 // that break.
1440 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001441 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001442 if (stmt.get() == unconditionalBreakStmt) {
1443 move_all_but_break(stmt, &caseStmts);
1444 unconditionalBreakStmt = nullptr;
1445 break;
1446 }
1447
1448 caseStmts.push_back(std::move(stmt));
1449 }
1450 }
1451
1452 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1453
1454 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001455 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001456}
1457
Ethan Nicholascb670962017-04-20 19:31:52 -04001458void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001459 BasicBlock& b,
1460 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001461 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001462 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001463 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001464 switch (stmt->kind()) {
1465 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001466 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001467 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001468 (!varDecl.value() ||
1469 !varDecl.value()->hasSideEffects())) {
1470 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001471 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001472 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001473 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001474 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001475 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001476 // There can still be (soon to be removed) references to the variable at this point.
1477 // Allowing the VarDeclaration to be destroyed here will break those variable's
1478 // initialValue()s, so we hang on to them until optimization is finished.
1479 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1480 usage);
1481 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001482 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001483 }
1484 break;
1485 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001486 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001487 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001488 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001489 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001490 if (i.test()->as<BoolLiteral>().value()) {
1491 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001492 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001493 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001494 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001495 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001496 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001497 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001498 }
1499 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001500 optimizationContext->fUpdated = true;
1501 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001502 break;
1503 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001504 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001505 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001506 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001507 optimizationContext->fUpdated = true;
1508 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001509 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001510 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001511 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001512 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001513 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001514 (*iter)->setStatement(
1515 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001516 } else {
1517 // no if, no else, no test side effects, kill the whole if
1518 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001519 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001520 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001521 optimizationContext->fUpdated = true;
1522 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001523 }
1524 break;
1525 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001526 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001527 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001528 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001529 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001530 // switch is constant, replace it with the case that matches
1531 bool found = false;
1532 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001533 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1534 if (!c->value()) {
1535 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001536 continue;
1537 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001538 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001539 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001540 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001541 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001542 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001543 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001544 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001545 break;
1546 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001547 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1548 optimizationContext->fSilences.find(&s) ==
1549 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001550 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001551 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001552 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001553 }
1554 return; // can't simplify
1555 }
1556 }
1557 }
1558 if (!found) {
1559 // no matching case. use default if it exists, or kill the whole thing
1560 if (defaultCase) {
1561 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1562 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001563 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001564 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001565 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1566 optimizationContext->fSilences.find(&s) ==
1567 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001568 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001569 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001570 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001571 }
1572 return; // can't simplify
1573 }
1574 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001575 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001576 }
1577 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001578 optimizationContext->fUpdated = true;
1579 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001580 }
1581 break;
1582 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001583 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001584 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001585 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001586 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001587 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001588 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001589 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001590 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001591 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001592 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001593 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001594 }
1595 break;
1596 }
1597 default:
1598 break;
1599 }
1600}
1601
Brian Osman010ce6a2020-10-19 16:34:10 -04001602bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001603 bool madeChanges = false;
1604
Ethan Nicholascb670962017-04-20 19:31:52 -04001605 CFG cfg = CFGGenerator().getCFG(f);
1606 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001607
1608 // check for unreachable code
1609 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001610 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001611 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
John Stiles0cc193a2020-09-09 09:39:34 -04001612 const BasicBlock::Node& node = block.fNodes[0];
John Stilesc1129322021-02-03 10:13:42 -05001613 int offset = node.isStatement() ? (*node.statement())->fOffset
1614 : (*node.expression())->fOffset;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001615 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001616 }
1617 }
1618 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001619 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001620 }
1621
Ethan Nicholascb670962017-04-20 19:31:52 -04001622 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001623 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001624 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001625 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001626 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001627 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001628 cfg = CFGGenerator().getCFG(f);
1629 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001630 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001631 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001632
John Stiles7d3f0892020-11-03 11:35:01 -05001633 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001634 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001635
1636 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1637 if (eliminatedBlockIds.test(blockId)) {
1638 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1639 optimizationContext.fUpdated = true;
1640 optimizationContext.fNeedsRescan = true;
1641 break;
1642 }
1643
1644 BasicBlock& b = cfg.fBlocks[blockId];
1645 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001646 // Block was reachable before optimization, but has since become unreachable. In
1647 // addition to being dead code, it's broken - since control flow can't reach it, no
1648 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001649 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001650 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001651 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001652 // Eliminating a node runs the risk of eliminating that node's exits as
1653 // well. Keep track of this and do a rescan if we are about to access one
1654 // of these.
1655 for (BlockId id : b.fExits) {
1656 eliminatedBlockIds.set(id);
1657 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001658 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001659 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001660 }
1661 }
1662 continue;
1663 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001664 DefinitionMap definitions = b.fBefore;
1665
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001666 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1667 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001668 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001669 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001670 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001671 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001672 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001673 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001674 break;
1675 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001676 this->addDefinitions(*iter, &definitions);
1677 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001678
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001679 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001680 break;
1681 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001682 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001683 madeChanges |= optimizationContext.fUpdated;
1684 } while (optimizationContext.fUpdated);
1685 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001686
Ethan Nicholas91a10532017-06-22 11:24:38 -04001687 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001688 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001689 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1690 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001691 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001692 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001693 switch (s.kind()) {
1694 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001695 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001696 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001697 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001698 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001699 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001700 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001701 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001702 if (s.as<SwitchStatement>().isStatic() &&
1703 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1704 optimizationContext.fSilences.find(&s) ==
1705 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001706 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001707 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001708 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001709 break;
1710 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001711 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001712 break;
1713 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001714 } else {
1715 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001716 }
1717 }
1718 }
1719
ethannicholas22f939e2016-10-13 13:25:34 -07001720 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001721 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001722 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001723 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001724 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001725 }
1726 }
John Stiles0cc193a2020-09-09 09:39:34 -04001727
1728 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001729}
1730
Brian Osman32d53552020-09-23 13:55:20 -04001731std::unique_ptr<Program> Compiler::convertProgram(
1732 Program::Kind kind,
1733 String text,
1734 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001735 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
1736 SkASSERT(!externalFunctions || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001737
Brian Osman0006ad02020-11-18 15:38:39 -05001738 // Loading and optimizing our base module might reset the inliner, so do that first,
1739 // *then* configure the inliner with the settings for this program.
1740 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1741
ethannicholasb3058bd2016-07-01 08:22:01 -07001742 fErrorText = "";
1743 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001744 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001745
1746 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001747 std::unique_ptr<String> textPtr(new String(std::move(text)));
1748 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001749
John Stiles5c7bb322020-10-22 11:09:15 -04001750 // Enable node pooling while converting and optimizing the program for a performance boost.
1751 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001752 std::unique_ptr<Pool> pool;
1753 if (fCaps->useNodePools()) {
1754 pool = Pool::Create();
1755 pool->attachToThread();
1756 }
Brian Osman0006ad02020-11-18 15:38:39 -05001757 IRGenerator::IRBundle ir =
1758 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001759 textPtr->c_str(), textPtr->size(), externalFunctions);
John Stiles5c7bb322020-10-22 11:09:15 -04001760 auto program = std::make_unique<Program>(kind,
1761 std::move(textPtr),
1762 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001763 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001764 fContext,
1765 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001766 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001767 std::move(ir.fModifiers),
1768 std::move(ir.fSymbolTable),
1769 std::move(pool),
1770 ir.fInputs);
1771 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001772 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001773 // Do not return programs that failed to compile.
1774 } else if (settings.fOptimize && !this->optimize(*program)) {
1775 // Do not return programs that failed to optimize.
1776 } else {
1777 // We have a successful program!
1778 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001779 }
John Stiles5c7bb322020-10-22 11:09:15 -04001780
Brian Osman28f702c2021-02-02 11:52:07 -05001781 if (program->fPool) {
1782 program->fPool->detachFromThread();
1783 }
John Stiles5c7bb322020-10-22 11:09:15 -04001784 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001785}
1786
Brian Osman0006ad02020-11-18 15:38:39 -05001787bool Compiler::optimize(LoadedModule& module) {
1788 SkASSERT(!fErrorCount);
1789 Program::Settings settings;
1790 fIRGenerator->fKind = module.fKind;
1791 fIRGenerator->fSettings = &settings;
1792 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1793
1794 fInliner.reset(fModifiers.back().get(), &settings);
1795
1796 while (fErrorCount == 0) {
1797 bool madeChanges = false;
1798
1799 // Scan and optimize based on the control-flow graph for each function.
1800 for (const auto& element : module.fElements) {
1801 if (element->is<FunctionDefinition>()) {
1802 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1803 }
1804 }
1805
1806 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001807 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001808
1809 if (!madeChanges) {
1810 break;
1811 }
1812 }
1813 return fErrorCount == 0;
1814}
1815
Ethan Nicholas00543112018-07-31 09:44:36 -04001816bool Compiler::optimize(Program& program) {
1817 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001818 fIRGenerator->fKind = program.fKind;
1819 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001820 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001821
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001822 while (fErrorCount == 0) {
1823 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001824
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001825 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001826 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001827 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001828 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001829 }
1830 }
1831
1832 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001833 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001834
1835 // Remove dead functions. We wait until after analysis so that we still report errors,
1836 // even in unused code.
1837 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001838 auto isDeadFunction = [&](const ProgramElement* element) {
1839 if (!element->is<FunctionDefinition>()) {
1840 return false;
1841 }
1842 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1843 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1844 usage->remove(*element);
1845 madeChanges = true;
1846 return true;
1847 }
1848 return false;
1849 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001850 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001851 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001852 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001853 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001854 }),
1855 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001856 program.fSharedElements.erase(
1857 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1858 isDeadFunction),
1859 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001860 }
1861
1862 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001863 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001864 auto isDeadVariable = [&](const ProgramElement* element) {
1865 if (!element->is<GlobalVarDeclaration>()) {
1866 return false;
1867 }
1868 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1869 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1870 if (usage->isDead(varDecl.var())) {
1871 madeChanges = true;
1872 return true;
1873 }
1874 return false;
1875 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001876 program.fElements.erase(
1877 std::remove_if(program.fElements.begin(), program.fElements.end(),
1878 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001879 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001880 }),
1881 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001882 program.fSharedElements.erase(
1883 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1884 isDeadVariable),
1885 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001886 }
John Stiles73a6bff2020-09-09 13:40:37 -04001887
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001888 if (!madeChanges) {
1889 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001890 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001891 }
1892 return fErrorCount == 0;
1893}
1894
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001895#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1896
Ethan Nicholas00543112018-07-31 09:44:36 -04001897bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001898#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001899 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001900 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001901 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001902 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001903 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001904 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001905 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001906 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001907 String errors;
1908 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1909 const char* m) {
1910 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001911 };
1912 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001913
1914 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1915 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1916 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1917 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1918
1919 if (!result) {
1920#if defined(SKSL_STANDALONE)
1921 // Convert the string-stream to a SPIR-V disassembly.
1922 std::string disassembly;
1923 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1924 errors.append(disassembly);
1925 }
1926 this->error(-1, errors);
1927#else
1928 SkDEBUGFAILF("%s", errors.c_str());
1929#endif
1930 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001931 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001932 }
1933#else
Brian Osman88cda172020-10-09 12:05:16 -04001934 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001935 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001936 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001937#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001938 return result;
1939}
1940
Ethan Nicholas00543112018-07-31 09:44:36 -04001941bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001942 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001943 bool result = this->toSPIRV(program, buffer);
1944 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001945 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001946 }
1947 return result;
1948}
1949
Ethan Nicholas00543112018-07-31 09:44:36 -04001950bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001951 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001952 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001953 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001954 return result;
1955}
1956
Ethan Nicholas00543112018-07-31 09:44:36 -04001957bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001958 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001959 bool result = this->toGLSL(program, buffer);
1960 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001961 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001962 }
1963 return result;
1964}
1965
Brian Osmanc0243912020-02-19 15:35:26 -05001966bool Compiler::toHLSL(Program& program, String* out) {
1967 String spirv;
1968 if (!this->toSPIRV(program, &spirv)) {
1969 return false;
1970 }
1971
1972 return SPIRVtoHLSL(spirv, out);
1973}
1974
Ethan Nicholas00543112018-07-31 09:44:36 -04001975bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001976 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001977 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001978 return result;
1979}
1980
Ethan Nicholas00543112018-07-31 09:44:36 -04001981bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001982 StringStream buffer;
1983 bool result = this->toMetal(program, buffer);
1984 if (result) {
1985 *out = buffer.str();
1986 }
1987 return result;
1988}
1989
Greg Daniela28ea672020-09-25 11:12:56 -04001990#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001991bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001992 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001993 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001994 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001995 return result;
1996}
1997
Ethan Nicholas00543112018-07-31 09:44:36 -04001998bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001999 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002000 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002001 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002002 return result;
2003}
Greg Daniela28ea672020-09-25 11:12:56 -04002004#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002005
Ethan Nicholas2a479a52020-08-18 16:29:45 -04002006#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04002007
2008#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04002009bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04002010 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04002011 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05002012 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04002013 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002014 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05002015 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04002016 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04002017 return result;
2018}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04002019#endif
2020
Brian Osman401a0092020-09-10 14:47:24 -04002021const char* Compiler::OperatorName(Token::Kind op) {
2022 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002023 case Token::Kind::TK_PLUS: return "+";
2024 case Token::Kind::TK_MINUS: return "-";
2025 case Token::Kind::TK_STAR: return "*";
2026 case Token::Kind::TK_SLASH: return "/";
2027 case Token::Kind::TK_PERCENT: return "%";
2028 case Token::Kind::TK_SHL: return "<<";
2029 case Token::Kind::TK_SHR: return ">>";
2030 case Token::Kind::TK_LOGICALNOT: return "!";
2031 case Token::Kind::TK_LOGICALAND: return "&&";
2032 case Token::Kind::TK_LOGICALOR: return "||";
2033 case Token::Kind::TK_LOGICALXOR: return "^^";
2034 case Token::Kind::TK_BITWISENOT: return "~";
2035 case Token::Kind::TK_BITWISEAND: return "&";
2036 case Token::Kind::TK_BITWISEOR: return "|";
2037 case Token::Kind::TK_BITWISEXOR: return "^";
2038 case Token::Kind::TK_EQ: return "=";
2039 case Token::Kind::TK_EQEQ: return "==";
2040 case Token::Kind::TK_NEQ: return "!=";
2041 case Token::Kind::TK_LT: return "<";
2042 case Token::Kind::TK_GT: return ">";
2043 case Token::Kind::TK_LTEQ: return "<=";
2044 case Token::Kind::TK_GTEQ: return ">=";
2045 case Token::Kind::TK_PLUSEQ: return "+=";
2046 case Token::Kind::TK_MINUSEQ: return "-=";
2047 case Token::Kind::TK_STAREQ: return "*=";
2048 case Token::Kind::TK_SLASHEQ: return "/=";
2049 case Token::Kind::TK_PERCENTEQ: return "%=";
2050 case Token::Kind::TK_SHLEQ: return "<<=";
2051 case Token::Kind::TK_SHREQ: return ">>=";
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002052 case Token::Kind::TK_BITWISEANDEQ: return "&=";
2053 case Token::Kind::TK_BITWISEOREQ: return "|=";
2054 case Token::Kind::TK_BITWISEXOREQ: return "^=";
2055 case Token::Kind::TK_PLUSPLUS: return "++";
2056 case Token::Kind::TK_MINUSMINUS: return "--";
2057 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002058 default:
John Stilesf57207b2021-02-02 17:50:34 -05002059 SK_ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002060 }
2061}
2062
2063
2064bool Compiler::IsAssignment(Token::Kind op) {
2065 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002066 case Token::Kind::TK_EQ: // fall through
2067 case Token::Kind::TK_PLUSEQ: // fall through
2068 case Token::Kind::TK_MINUSEQ: // fall through
2069 case Token::Kind::TK_STAREQ: // fall through
2070 case Token::Kind::TK_SLASHEQ: // fall through
2071 case Token::Kind::TK_PERCENTEQ: // fall through
2072 case Token::Kind::TK_SHLEQ: // fall through
2073 case Token::Kind::TK_SHREQ: // fall through
2074 case Token::Kind::TK_BITWISEOREQ: // fall through
2075 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05002076 case Token::Kind::TK_BITWISEANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002077 return true;
2078 default:
2079 return false;
2080 }
2081}
2082
Brian Osman401a0092020-09-10 14:47:24 -04002083Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
2084 switch (op) {
2085 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
2086 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
2087 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
2088 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
2089 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
2090 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
2091 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
2092 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
2093 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
2094 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
Brian Osman401a0092020-09-10 14:47:24 -04002095 default: return op;
2096 }
2097}
2098
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002099Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05002100 if (fSource && offset >= 0) {
2101 int line = 1;
2102 int column = 1;
2103 for (int i = 0; i < offset; i++) {
2104 if ((*fSource)[i] == '\n') {
2105 ++line;
2106 column = 1;
2107 }
2108 else {
2109 ++column;
2110 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002111 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05002112 return Position(line, column);
2113 } else {
2114 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002115 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002116}
2117
2118void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002119 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002120 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05002121 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05002122 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07002123}
2124
John Stiles8d3642e2021-01-22 09:50:04 -05002125void Compiler::setErrorCount(int c) {
2126 if (c < fErrorCount) {
2127 fErrorText.resize(fErrorTextLength[c]);
2128 fErrorTextLength.resize(c);
2129 fErrorCount = c;
2130 }
2131}
2132
Ethan Nicholas95046142021-01-07 10:57:27 -05002133String Compiler::errorText(bool showCount) {
2134 if (showCount) {
2135 this->writeErrorCount();
2136 }
Ethan Nicholas00543112018-07-31 09:44:36 -04002137 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002138 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05002139 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07002140 return result;
2141}
2142
2143void Compiler::writeErrorCount() {
2144 if (fErrorCount) {
2145 fErrorText += to_string(fErrorCount) + " error";
2146 if (fErrorCount > 1) {
2147 fErrorText += "s";
2148 }
2149 fErrorText += "\n";
2150 }
2151}
2152
John Stilesa6841be2020-08-06 14:11:56 -04002153} // namespace SkSL