blob: b7615c7dcc80e27950bc9a0d061e6b13605887c5 [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:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500579#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400580 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500581#endif
582 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400583 }
584}
ethannicholas22f939e2016-10-13 13:25:34 -0700585
Ethan Nicholascb670962017-04-20 19:31:52 -0400586/**
587 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
588 * to a dead target and lack of side effects on the left hand side.
589 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400590static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400591 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400592 return false;
593 }
John Stiles2d4f9592020-10-30 10:29:12 -0400594 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400595}
596
597void Compiler::computeDataFlow(CFG* cfg) {
598 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400599
600 // We set bits in the "processed" set after a block has been scanned.
601 SkBitSet processedSet(cfg->fBlocks.size());
602 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
603 processedSet.set(*blockId);
604 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700605 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400606}
607
608/**
609 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
610 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
611 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
612 * need to be regenerated).
613 */
John Stilesafbf8992020-08-18 10:08:21 -0400614static bool try_replace_expression(BasicBlock* b,
615 std::vector<BasicBlock::Node>::iterator* iter,
616 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400617 std::unique_ptr<Expression>* target = (*iter)->expression();
618 if (!b->tryRemoveExpression(iter)) {
619 *target = std::move(*newExpression);
620 return false;
621 }
622 *target = std::move(*newExpression);
623 return b->tryInsertExpression(iter, target);
624}
625
626/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400627 * Returns true if the expression is a constant numeric literal with the specified value, or a
628 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400629 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400630template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400631static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400632 switch (expr.kind()) {
633 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400634 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400635
Ethan Nicholase6592142020-09-08 10:22:09 -0400636 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400637 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400638
Ethan Nicholase6592142020-09-08 10:22:09 -0400639 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400640 const Constructor& constructor = expr.as<Constructor>();
641 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400642 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400643 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400644 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500645 if (constructor.componentType().isFloat()) {
646 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400647 if (constructor.getFVecComponent(i) != value) {
648 return false;
649 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500650 }
651 return true;
652 } else if (constructor.componentType().isInteger()) {
653 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400654 if (constructor.getIVecComponent(i) != value) {
655 return false;
656 }
657 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500658 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400659 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500660 // Other types (e.g. boolean) might occur, but aren't supported here.
661 return false;
John Stiles9d944232020-08-19 09:56:49 -0400662
Ethan Nicholase6592142020-09-08 10:22:09 -0400663 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400664 SkASSERT(constructor.arguments().size() == 1);
665 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400666
667 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400668 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400669 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400670 }
671 return false;
672 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400673 default:
674 return false;
675 }
676}
677
678/**
679 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
680 * and CFG structures).
681 */
John Stilesafbf8992020-08-18 10:08:21 -0400682static void delete_left(BasicBlock* b,
683 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400684 Compiler::OptimizationContext* optimizationContext) {
685 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400686 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400687 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400688 Expression& left = *bin.left();
689 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400690 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400691 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400692 if (bin.getOperator() == Token::Kind::TK_EQ) {
693 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400694 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400695 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400696 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400697 // Remove references within LHS.
698 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400699 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400700 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400701 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400702 return;
703 }
704 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400705 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400706 return;
707 }
708 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400709 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400710 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400711 return;
712 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400713 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400714 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400715}
716
717/**
718 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
719 * CFG structures).
720 */
John Stilesafbf8992020-08-18 10:08:21 -0400721static void delete_right(BasicBlock* b,
722 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400723 Compiler::OptimizationContext* optimizationContext) {
724 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400725 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400726 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400727 std::unique_ptr<Expression>& leftPointer = bin.left();
728 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400729 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400730 // Remove references within RHS.
731 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400732 if (!b->tryRemoveExpressionBefore(iter, &right)) {
733 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400734 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400735 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400736 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400737 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400738 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400739 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400740 return;
741 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400742 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400743 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400744 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400745 return;
746 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400747 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400748 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400749}
750
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400751/**
752 * Constructs the specified type using a single argument.
753 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400754static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400755 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400756 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400757 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400758 return result;
759}
760
761/**
762 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
763 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
764 */
765static void vectorize(BasicBlock* b,
766 std::vector<BasicBlock::Node>::iterator* iter,
767 const Type& type,
768 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400769 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400770 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500771 SkASSERT(type.isVector());
772 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400773 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400774 std::unique_ptr<Expression>* target = (*iter)->expression();
775 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400776 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400777 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400778 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400779 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400780 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400781 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400782 }
783 }
784}
785
786/**
787 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
788 * left to yield vec<n>(x).
789 */
790static void vectorize_left(BasicBlock* b,
791 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400792 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400793 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400794 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400795 optimizationContext->fUsage->remove(bin.right().get());
796 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400797}
798
799/**
800 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
801 * right to yield vec<n>(y).
802 */
803static void vectorize_right(BasicBlock* b,
804 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400805 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400806 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400807 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400808 optimizationContext->fUsage->remove(bin.left().get());
809 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400810}
811
812// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400813static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400814 switch (expr.kind()) {
815 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400816 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400817 break;
818 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400819 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400820 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400821 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400822 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400823 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400824 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400825 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400826 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400827 break;
828 default:
829 ABORT("shouldn't be writing to this kind of expression\n");
830 break;
831 }
832}
833
Ethan Nicholascb670962017-04-20 19:31:52 -0400834void Compiler::simplifyExpression(DefinitionMap& definitions,
835 BasicBlock& b,
836 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400837 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400838 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400839 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500840
Ethan Nicholascb670962017-04-20 19:31:52 -0400841 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400842 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
843 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400844 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400845 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400846 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400847 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400848 // Remove references within 'expr', add references within 'optimized'
849 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400850 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400851 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400852 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400853 }
John Stiles70025e52020-09-28 16:08:58 -0400854 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400855 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400856 }
857 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400858 switch (expr->kind()) {
859 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400860 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400861 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400862 if (ref.refKind() != VariableReference::RefKind::kWrite &&
863 ref.refKind() != VariableReference::RefKind::kPointer &&
864 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400865 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
866 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000867 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400868 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400869 }
870 break;
871 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400872 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400873 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400874 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400875 // ternary has a constant test, replace it with either the true or
876 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400877 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400878 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400879 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400880 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400881 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400882 optimizationContext->fUpdated = true;
883 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400884 }
885 break;
886 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400887 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400888 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400889 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400890 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400891 break;
892 }
John Stiles2d4f9592020-10-30 10:29:12 -0400893 Expression& left = *bin->left();
894 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400895 const Type& leftType = left.type();
896 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400897 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500898 if ((!leftType.isScalar() && !leftType.isVector()) ||
899 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400900 break;
901 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400902 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400903 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400904 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500905 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400906 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400907 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400908 } else {
909 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400910 // 1 * float4(x) -> float4(x)
911 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400912 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400913 }
914 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400915 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500916 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400917 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400918 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400919 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400920 } else {
921 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400922 // float4(0) * x -> float4(0)
923 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400924 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400925 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500926 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400927 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400928 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400929 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500930 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400931 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400932 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400933 } else {
934 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400935 // float4(x) * 1 -> float4(x)
936 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400937 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400938 }
939 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400940 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500941 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400942 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400943 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400944 } else {
945 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400946 // x * float4(0) -> float4(0)
947 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400948 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400949 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500950 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400951 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400952 }
953 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400954 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400955 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500956 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400957 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400958 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400959 } else {
960 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400961 // 0 + float4(x) -> float4(x)
962 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400963 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400964 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400965 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500966 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400967 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400968 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400969 } else {
970 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400971 // float4(x) + 0 -> float4(x)
972 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400973 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400974 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400975 }
976 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400977 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400978 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500979 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400980 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400981 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400982 } else {
983 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400984 // float4(x) - 0 -> float4(x)
985 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400986 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400987 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400988 }
989 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400990 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400991 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500992 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400993 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400994 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400995 } else {
996 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400997 // float4(x) / 1 -> float4(x)
998 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400999 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001000 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001001 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -05001002 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001003 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001004 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001005 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001006 } else {
1007 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001008 // float4(0) / x -> float4(0)
1009 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001010 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001011 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001012 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001013 }
1014 }
1015 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001016 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001017 if (is_constant(right, 0)) {
1018 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001019 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001020 }
1021 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001022 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001023 if (is_constant(right, 0)) {
1024 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001025 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001026 }
1027 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001028 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001029 if (is_constant(right, 1)) {
1030 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001031 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001032 }
1033 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001034 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001035 if (is_constant(right, 1)) {
1036 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001037 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001038 }
1039 break;
1040 default:
1041 break;
1042 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001043 break;
1044 }
John Stilesf5c1d042020-11-21 23:26:07 -05001045 case Expression::Kind::kConstructor: {
1046 // Find constructors embedded inside constructors and flatten them out where possible.
1047 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
1048 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
1049 // Leave single-argument constructors alone, though. These might be casts or splats.
1050 Constructor& c = expr->as<Constructor>();
1051 if (c.type().columns() > 1) {
1052 // Inspect each constructor argument to see if it's a candidate for flattening.
1053 // Remember matched arguments in a bitfield, "argsToOptimize".
1054 int argsToOptimize = 0;
1055 int currBit = 1;
1056 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1057 if (arg->is<Constructor>()) {
1058 Constructor& inner = arg->as<Constructor>();
1059 if (inner.arguments().size() > 1 &&
1060 inner.type().componentType() == c.type().componentType()) {
1061 argsToOptimize |= currBit;
1062 }
1063 }
1064 currBit <<= 1;
1065 }
1066 if (argsToOptimize) {
1067 // We found at least one argument that could be flattened out. Re-walk the
1068 // constructor args and flatten the candidates we found during our initial pass.
1069 ExpressionArray flattened;
1070 flattened.reserve_back(c.type().columns());
1071 currBit = 1;
1072 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1073 if (argsToOptimize & currBit) {
1074 Constructor& inner = arg->as<Constructor>();
1075 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
1076 flattened.push_back(innerArg->clone());
1077 }
1078 } else {
1079 flattened.push_back(arg->clone());
1080 }
1081 currBit <<= 1;
1082 }
1083 auto optimized = std::unique_ptr<Expression>(
1084 new Constructor(c.fOffset, &c.type(), std::move(flattened)));
1085 // No fUsage change; no references have been added or removed anywhere.
1086 optimizationContext->fUpdated = true;
1087 if (!try_replace_expression(&b, iter, &optimized)) {
1088 optimizationContext->fNeedsRescan = true;
1089 return;
1090 }
1091 SkASSERT((*iter)->isExpression());
1092 break;
1093 }
1094 }
1095 break;
1096 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001097 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001098 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -05001099 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001100 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001101 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001102 for (int i = 0; i < (int) s.components().size(); ++i) {
1103 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001104 identity = false;
1105 break;
1106 }
1107 }
1108 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001109 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001110 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001111 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001112 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001113 return;
1114 }
John Stiles70025e52020-09-28 16:08:58 -04001115 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001116 break;
1117 }
1118 }
John Stiles108bbe22020-11-18 11:10:38 -05001119 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1120 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001121 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001122 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001123 for (int c : s.components()) {
1124 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001125 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001126 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001127 final));
John Stilesd2f51b12021-01-07 18:12:31 -05001128 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -05001129 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -05001130 try_replace_expression(&b, iter, &replacement);
1131 optimizationContext->fUpdated = true;
1132 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001133 break;
1134 }
1135 // Optimize swizzles of constructors.
1136 if (s.base()->is<Constructor>()) {
1137 Constructor& base = s.base()->as<Constructor>();
1138 std::unique_ptr<Expression> replacement;
1139 const Type& componentType = base.type().componentType();
1140 int swizzleSize = s.components().size();
1141
1142 // The IR generator has already converted any zero/one swizzle components into
1143 // constructors containing zero/one args. Confirm that this is true by checking that
1144 // our swizzle components are all `xyzw` (values 0 through 3).
1145 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1146 [](int8_t c) { return c >= 0 && c <= 3; }));
1147
John Stiles9aeed132020-11-24 17:36:06 -05001148 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001149 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1150 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001151 const Expression& argument = *base.arguments().front();
1152 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1153 /*rows=*/1);
1154 replacement = Constructor::SimplifyConversion(constructorType, argument);
1155 if (!replacement) {
1156 ExpressionArray newArgs;
1157 newArgs.push_back(argument.clone());
1158 replacement = std::make_unique<Constructor>(base.fOffset, &constructorType,
1159 std::move(newArgs));
1160 }
John Stiles108bbe22020-11-18 11:10:38 -05001161
John Stilesa60ac0c2020-12-22 08:59:51 -05001162 // We're replacing an expression with a cloned version; we'll need a rescan.
1163 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1164 // reference counts.
1165 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001166 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001167 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001168 break;
1169 }
1170
John Stiles0777ac42020-11-19 11:06:47 -05001171 // Swizzles can duplicate some elements and discard others, e.g.
1172 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1173 // - Expressions with side effects need to occur exactly once, even if they
1174 // would otherwise be swizzle-eliminated
1175 // - Non-trivial expressions should not be repeated, but elimination is OK.
1176 //
1177 // Look up the argument for the constructor at each index. This is typically simple
1178 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1179 // seems. This example would result in:
1180 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1181 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1182 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1183 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1184 struct ConstructorArgMap {
1185 int8_t fArgIndex;
1186 int8_t fComponent;
1187 };
1188
1189 int numConstructorArgs = base.type().columns();
1190 ConstructorArgMap argMap[4] = {};
1191 int writeIdx = 0;
1192 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1193 const Expression& expr = *base.arguments()[argIdx];
1194 int argWidth = expr.type().columns();
1195 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1196 argMap[writeIdx].fArgIndex = argIdx;
1197 argMap[writeIdx].fComponent = componentIdx;
1198 ++writeIdx;
1199 }
1200 }
1201 SkASSERT(writeIdx == numConstructorArgs);
1202
1203 // Count up the number of times each constructor argument is used by the
1204 // swizzle.
1205 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1206 // - bar.yz is referenced 3 times, by `.x_xy`
1207 // - half(foo) is referenced 1 time, by `._w__`
1208 int8_t exprUsed[4] = {};
1209 for (int c : s.components()) {
1210 exprUsed[argMap[c].fArgIndex]++;
1211 }
1212
1213 bool safeToOptimize = true;
1214 for (int index = 0; index < numConstructorArgs; ++index) {
1215 int8_t constructorArgIndex = argMap[index].fArgIndex;
1216 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1217
1218 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001219 if (exprUsed[constructorArgIndex] > 1 &&
1220 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001221 safeToOptimize = false;
1222 break;
1223 }
1224 // Check that side-effect-bearing expressions are swizzled in exactly once.
1225 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1226 safeToOptimize = false;
1227 break;
1228 }
1229 }
1230
1231 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001232 struct ReorderedArgument {
1233 int8_t fArgIndex;
1234 ComponentArray fComponents;
1235 };
1236 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001237 for (int c : s.components()) {
1238 const ConstructorArgMap& argument = argMap[c];
1239 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1240
John Stiles9aeed132020-11-24 17:36:06 -05001241 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001242 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001243 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001244 reorderedArgs.push_back({argument.fArgIndex,
1245 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001246 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001247 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001248 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001249 if (reorderedArgs.empty() ||
1250 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1251 // This can't be combined with the previous argument. Add a new one.
1252 reorderedArgs.push_back({argument.fArgIndex,
1253 ComponentArray{argument.fComponent}});
1254 } else {
1255 // Since we know this argument uses components, it should already
1256 // have at least one component set.
1257 SkASSERT(!reorderedArgs.back().fComponents.empty());
1258 // Build up the current argument with one more component.
1259 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1260 }
John Stiles0777ac42020-11-19 11:06:47 -05001261 }
1262 }
John Stilesd9076cb2020-11-19 12:18:36 -05001263
1264 // Convert our reordered argument list to an actual array of expressions, with
1265 // the new order and any new inner swizzles that need to be applied. Note that
1266 // we expect followup passes to clean up the inner swizzles.
1267 ExpressionArray newArgs;
1268 newArgs.reserve_back(swizzleSize);
1269 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1270 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1271 if (reorderedArg.fComponents.empty()) {
1272 newArgs.push_back(baseArg.clone());
1273 } else {
1274 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1275 reorderedArg.fComponents));
1276 }
1277 }
1278
1279 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001280 replacement = std::make_unique<Constructor>(
1281 base.fOffset,
1282 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1283 std::move(newArgs));
1284
John Stilesa60ac0c2020-12-22 08:59:51 -05001285 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001286 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001287
1288 // We're replacing an expression with a cloned version; we'll need a rescan.
1289 try_replace_expression(&b, iter, &replacement);
1290 optimizationContext->fUpdated = true;
1291 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001292 }
John Stiles108bbe22020-11-18 11:10:38 -05001293 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001294 }
John Stiles30212b72020-06-11 17:55:07 -04001295 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001296 }
1297 default:
1298 break;
1299 }
1300}
1301
John Stiles92219b42020-06-15 12:32:24 -04001302// Returns true if this statement could potentially execute a break at the current level. We ignore
1303// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001304static bool contains_conditional_break(Statement& stmt) {
1305 class ContainsConditionalBreak : public ProgramVisitor {
1306 public:
1307 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001308 switch (stmt.kind()) {
1309 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001310 return this->INHERITED::visitStatement(stmt);
1311
Ethan Nicholase6592142020-09-08 10:22:09 -04001312 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001313 return fInConditional > 0;
1314
Ethan Nicholase6592142020-09-08 10:22:09 -04001315 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001316 ++fInConditional;
1317 bool result = this->INHERITED::visitStatement(stmt);
1318 --fInConditional;
1319 return result;
1320 }
1321
1322 default:
1323 return false;
1324 }
1325 }
1326
1327 int fInConditional = 0;
1328 using INHERITED = ProgramVisitor;
1329 };
1330
1331 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001332}
1333
Ethan Nicholas5005a222018-08-24 13:06:27 -04001334// returns true if this statement definitely executes a break at the current level (we ignore
1335// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001336static bool contains_unconditional_break(Statement& stmt) {
1337 class ContainsUnconditionalBreak : public ProgramVisitor {
1338 public:
1339 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001340 switch (stmt.kind()) {
1341 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001342 return this->INHERITED::visitStatement(stmt);
1343
Ethan Nicholase6592142020-09-08 10:22:09 -04001344 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001345 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001346
1347 default:
1348 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001349 }
John Stilesb92641c2020-08-31 18:09:01 -04001350 }
John Stiles92219b42020-06-15 12:32:24 -04001351
John Stilesb92641c2020-08-31 18:09:01 -04001352 using INHERITED = ProgramVisitor;
1353 };
John Stiles92219b42020-06-15 12:32:24 -04001354
John Stilesb92641c2020-08-31 18:09:01 -04001355 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001356}
1357
John Stiles8f2a0cf2020-10-13 12:48:21 -04001358static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001359 switch (stmt->kind()) {
1360 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001361 // Recurse into the block.
1362 Block& block = static_cast<Block&>(*stmt);
1363
John Stiles8f2a0cf2020-10-13 12:48:21 -04001364 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001365 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001366 for (std::unique_ptr<Statement>& stmt : block.children()) {
1367 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001368 }
John Stiles92219b42020-06-15 12:32:24 -04001369
1370 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001371 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001372 break;
John Stiles92219b42020-06-15 12:32:24 -04001373 }
1374
Ethan Nicholase6592142020-09-08 10:22:09 -04001375 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001376 // Do not append a break to the target.
1377 break;
1378
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001379 default:
John Stiles92219b42020-06-15 12:32:24 -04001380 // Append normal statements to the target.
1381 target->push_back(std::move(stmt));
1382 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001383 }
1384}
1385
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001386// Returns a block containing all of the statements that will be run if the given case matches
1387// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1388// broken by this call and must then be discarded).
1389// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1390// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001391static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1392 SwitchCase* caseToCapture) {
1393 // We have to be careful to not move any of the pointers until after we're sure we're going to
1394 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1395 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001396 auto iter = switchStatement->cases().begin();
1397 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001398 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001399 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001400 }
John Stiles92219b42020-06-15 12:32:24 -04001401 }
1402
1403 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1404 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1405 // statements that we can use for simplification.
1406 auto startIter = iter;
1407 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001408 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001409 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001410 if (contains_conditional_break(*stmt)) {
1411 // We can't reduce switch-cases to a block when they have conditional breaks.
1412 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001413 }
John Stiles92219b42020-06-15 12:32:24 -04001414
1415 if (contains_unconditional_break(*stmt)) {
1416 // We found an unconditional break. We can use this block, but we need to strip
1417 // out the break statement.
1418 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001419 break;
1420 }
1421 }
John Stiles92219b42020-06-15 12:32:24 -04001422
1423 if (unconditionalBreakStmt != nullptr) {
1424 break;
1425 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001426 }
John Stiles92219b42020-06-15 12:32:24 -04001427
1428 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1429 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001430 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001431
1432 // We can move over most of the statements as-is.
1433 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001434 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001435 caseStmts.push_back(std::move(stmt));
1436 }
1437 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001438 }
John Stiles92219b42020-06-15 12:32:24 -04001439
1440 // If we found an unconditional break at the end, we need to move what we can while avoiding
1441 // that break.
1442 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001443 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001444 if (stmt.get() == unconditionalBreakStmt) {
1445 move_all_but_break(stmt, &caseStmts);
1446 unconditionalBreakStmt = nullptr;
1447 break;
1448 }
1449
1450 caseStmts.push_back(std::move(stmt));
1451 }
1452 }
1453
1454 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1455
1456 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001457 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001458}
1459
Ethan Nicholascb670962017-04-20 19:31:52 -04001460void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001461 BasicBlock& b,
1462 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001463 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001464 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001465 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001466 switch (stmt->kind()) {
1467 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001468 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001469 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001470 (!varDecl.value() ||
1471 !varDecl.value()->hasSideEffects())) {
1472 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001473 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001474 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001475 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001476 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001477 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001478 // There can still be (soon to be removed) references to the variable at this point.
1479 // Allowing the VarDeclaration to be destroyed here will break those variable's
1480 // initialValue()s, so we hang on to them until optimization is finished.
1481 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1482 usage);
1483 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001484 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001485 }
1486 break;
1487 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001488 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001489 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001490 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001491 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001492 if (i.test()->as<BoolLiteral>().value()) {
1493 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001494 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001495 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001496 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001497 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001498 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001499 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001500 }
1501 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001502 optimizationContext->fUpdated = true;
1503 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001504 break;
1505 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001506 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001507 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001508 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001509 optimizationContext->fUpdated = true;
1510 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001511 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001512 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001513 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001514 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001515 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001516 (*iter)->setStatement(
1517 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001518 } else {
1519 // no if, no else, no test side effects, kill the whole if
1520 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001521 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001522 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001523 optimizationContext->fUpdated = true;
1524 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001525 }
1526 break;
1527 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001528 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001529 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001530 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001531 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001532 // switch is constant, replace it with the case that matches
1533 bool found = false;
1534 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001535 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1536 if (!c->value()) {
1537 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001538 continue;
1539 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001540 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001541 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001542 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001543 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001544 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001545 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001546 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001547 break;
1548 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001549 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1550 optimizationContext->fSilences.find(&s) ==
1551 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001552 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001553 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001554 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001555 }
1556 return; // can't simplify
1557 }
1558 }
1559 }
1560 if (!found) {
1561 // no matching case. use default if it exists, or kill the whole thing
1562 if (defaultCase) {
1563 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1564 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001565 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001566 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001567 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1568 optimizationContext->fSilences.find(&s) ==
1569 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001570 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001571 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001572 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001573 }
1574 return; // can't simplify
1575 }
1576 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001577 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001578 }
1579 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001580 optimizationContext->fUpdated = true;
1581 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001582 }
1583 break;
1584 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001585 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001586 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001587 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001588 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001589 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001590 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001591 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001592 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001593 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001594 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001595 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001596 }
1597 break;
1598 }
1599 default:
1600 break;
1601 }
1602}
1603
Brian Osman010ce6a2020-10-19 16:34:10 -04001604bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001605 bool madeChanges = false;
1606
Ethan Nicholascb670962017-04-20 19:31:52 -04001607 CFG cfg = CFGGenerator().getCFG(f);
1608 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001609
1610 // check for unreachable code
1611 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001612 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001613 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001614 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001615 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001616 if (node.isStatement()) {
1617 offset = (*node.statement())->fOffset;
1618 } else {
1619 offset = (*node.expression())->fOffset;
1620 if ((*node.expression())->is<BoolLiteral>()) {
1621 // Function inlining can generate do { ... } while(false) loops which always
1622 // break, so the boolean condition is considered unreachable. Since not being
1623 // able to reach a literal is a non-issue in the first place, we don't report an
1624 // error in this case.
1625 continue;
1626 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001627 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001628 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001629 }
1630 }
1631 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001632 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001633 }
1634
Ethan Nicholascb670962017-04-20 19:31:52 -04001635 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001636 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001637 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001638 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001639 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001640 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001641 cfg = CFGGenerator().getCFG(f);
1642 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001643 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001644 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001645
John Stiles7d3f0892020-11-03 11:35:01 -05001646 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001647 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001648
1649 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1650 if (eliminatedBlockIds.test(blockId)) {
1651 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1652 optimizationContext.fUpdated = true;
1653 optimizationContext.fNeedsRescan = true;
1654 break;
1655 }
1656
1657 BasicBlock& b = cfg.fBlocks[blockId];
1658 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001659 // Block was reachable before optimization, but has since become unreachable. In
1660 // addition to being dead code, it's broken - since control flow can't reach it, no
1661 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001662 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001663 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001664 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001665 // Eliminating a node runs the risk of eliminating that node's exits as
1666 // well. Keep track of this and do a rescan if we are about to access one
1667 // of these.
1668 for (BlockId id : b.fExits) {
1669 eliminatedBlockIds.set(id);
1670 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001671 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001672 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001673 }
1674 }
1675 continue;
1676 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001677 DefinitionMap definitions = b.fBefore;
1678
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001679 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1680 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001681 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001682 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001683 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001684 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001685 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001686 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001687 break;
1688 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001689 this->addDefinitions(*iter, &definitions);
1690 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001691
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001692 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001693 break;
1694 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001695 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001696 madeChanges |= optimizationContext.fUpdated;
1697 } while (optimizationContext.fUpdated);
1698 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001699
Ethan Nicholas91a10532017-06-22 11:24:38 -04001700 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001701 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001702 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1703 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001704 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001705 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001706 switch (s.kind()) {
1707 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001708 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001709 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001710 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001711 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001712 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001713 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001714 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001715 if (s.as<SwitchStatement>().isStatic() &&
1716 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1717 optimizationContext.fSilences.find(&s) ==
1718 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001719 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001720 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001721 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001722 break;
1723 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001724 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001725 break;
1726 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001727 } else {
1728 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001729 }
1730 }
1731 }
1732
ethannicholas22f939e2016-10-13 13:25:34 -07001733 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001734 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001735 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001736 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001737 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001738 }
1739 }
John Stiles0cc193a2020-09-09 09:39:34 -04001740
1741 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001742}
1743
Brian Osman32d53552020-09-23 13:55:20 -04001744std::unique_ptr<Program> Compiler::convertProgram(
1745 Program::Kind kind,
1746 String text,
1747 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001748 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
1749 SkASSERT(!externalFunctions || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001750
Brian Osman0006ad02020-11-18 15:38:39 -05001751 // Loading and optimizing our base module might reset the inliner, so do that first,
1752 // *then* configure the inliner with the settings for this program.
1753 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1754
ethannicholasb3058bd2016-07-01 08:22:01 -07001755 fErrorText = "";
1756 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001757 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001758
1759 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001760 std::unique_ptr<String> textPtr(new String(std::move(text)));
1761 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001762
John Stiles5c7bb322020-10-22 11:09:15 -04001763 // Enable node pooling while converting and optimizing the program for a performance boost.
1764 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001765 std::unique_ptr<Pool> pool;
1766 if (fCaps->useNodePools()) {
1767 pool = Pool::Create();
1768 pool->attachToThread();
1769 }
Brian Osman0006ad02020-11-18 15:38:39 -05001770 IRGenerator::IRBundle ir =
1771 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001772 textPtr->c_str(), textPtr->size(), externalFunctions);
John Stiles5c7bb322020-10-22 11:09:15 -04001773 auto program = std::make_unique<Program>(kind,
1774 std::move(textPtr),
1775 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001776 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001777 fContext,
1778 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001779 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001780 std::move(ir.fModifiers),
1781 std::move(ir.fSymbolTable),
1782 std::move(pool),
1783 ir.fInputs);
1784 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001785 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001786 // Do not return programs that failed to compile.
1787 } else if (settings.fOptimize && !this->optimize(*program)) {
1788 // Do not return programs that failed to optimize.
1789 } else {
1790 // We have a successful program!
1791 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001792 }
John Stiles5c7bb322020-10-22 11:09:15 -04001793
Brian Osman28f702c2021-02-02 11:52:07 -05001794 if (program->fPool) {
1795 program->fPool->detachFromThread();
1796 }
John Stiles5c7bb322020-10-22 11:09:15 -04001797 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001798}
1799
Brian Osman0006ad02020-11-18 15:38:39 -05001800bool Compiler::optimize(LoadedModule& module) {
1801 SkASSERT(!fErrorCount);
1802 Program::Settings settings;
1803 fIRGenerator->fKind = module.fKind;
1804 fIRGenerator->fSettings = &settings;
1805 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1806
1807 fInliner.reset(fModifiers.back().get(), &settings);
1808
1809 while (fErrorCount == 0) {
1810 bool madeChanges = false;
1811
1812 // Scan and optimize based on the control-flow graph for each function.
1813 for (const auto& element : module.fElements) {
1814 if (element->is<FunctionDefinition>()) {
1815 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1816 }
1817 }
1818
1819 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001820 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001821
1822 if (!madeChanges) {
1823 break;
1824 }
1825 }
1826 return fErrorCount == 0;
1827}
1828
Ethan Nicholas00543112018-07-31 09:44:36 -04001829bool Compiler::optimize(Program& program) {
1830 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001831 fIRGenerator->fKind = program.fKind;
1832 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001833 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001834
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001835 while (fErrorCount == 0) {
1836 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001837
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001838 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001839 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001840 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001841 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001842 }
1843 }
1844
1845 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001846 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001847
1848 // Remove dead functions. We wait until after analysis so that we still report errors,
1849 // even in unused code.
1850 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001851 auto isDeadFunction = [&](const ProgramElement* element) {
1852 if (!element->is<FunctionDefinition>()) {
1853 return false;
1854 }
1855 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1856 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1857 usage->remove(*element);
1858 madeChanges = true;
1859 return true;
1860 }
1861 return false;
1862 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001863 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001864 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001865 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001866 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001867 }),
1868 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001869 program.fSharedElements.erase(
1870 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1871 isDeadFunction),
1872 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001873 }
1874
1875 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001876 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001877 auto isDeadVariable = [&](const ProgramElement* element) {
1878 if (!element->is<GlobalVarDeclaration>()) {
1879 return false;
1880 }
1881 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1882 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1883 if (usage->isDead(varDecl.var())) {
1884 madeChanges = true;
1885 return true;
1886 }
1887 return false;
1888 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001889 program.fElements.erase(
1890 std::remove_if(program.fElements.begin(), program.fElements.end(),
1891 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001892 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001893 }),
1894 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001895 program.fSharedElements.erase(
1896 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1897 isDeadVariable),
1898 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001899 }
John Stiles73a6bff2020-09-09 13:40:37 -04001900
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001901 if (!madeChanges) {
1902 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001903 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001904 }
1905 return fErrorCount == 0;
1906}
1907
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001908#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1909
Ethan Nicholas00543112018-07-31 09:44:36 -04001910bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001911#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001912 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001913 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001914 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001915 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001916 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001917 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001918 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001919 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001920 String errors;
1921 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1922 const char* m) {
1923 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001924 };
1925 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001926
1927 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1928 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1929 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1930 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1931
1932 if (!result) {
1933#if defined(SKSL_STANDALONE)
1934 // Convert the string-stream to a SPIR-V disassembly.
1935 std::string disassembly;
1936 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1937 errors.append(disassembly);
1938 }
1939 this->error(-1, errors);
1940#else
1941 SkDEBUGFAILF("%s", errors.c_str());
1942#endif
1943 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001944 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001945 }
1946#else
Brian Osman88cda172020-10-09 12:05:16 -04001947 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001948 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001949 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001950#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001951 return result;
1952}
1953
Ethan Nicholas00543112018-07-31 09:44:36 -04001954bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001955 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001956 bool result = this->toSPIRV(program, buffer);
1957 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001958 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001959 }
1960 return result;
1961}
1962
Ethan Nicholas00543112018-07-31 09:44:36 -04001963bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001964 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001965 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001966 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001967 return result;
1968}
1969
Ethan Nicholas00543112018-07-31 09:44:36 -04001970bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001971 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001972 bool result = this->toGLSL(program, buffer);
1973 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001974 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001975 }
1976 return result;
1977}
1978
Brian Osmanc0243912020-02-19 15:35:26 -05001979bool Compiler::toHLSL(Program& program, String* out) {
1980 String spirv;
1981 if (!this->toSPIRV(program, &spirv)) {
1982 return false;
1983 }
1984
1985 return SPIRVtoHLSL(spirv, out);
1986}
1987
Ethan Nicholas00543112018-07-31 09:44:36 -04001988bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001989 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001990 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001991 return result;
1992}
1993
Ethan Nicholas00543112018-07-31 09:44:36 -04001994bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001995 StringStream buffer;
1996 bool result = this->toMetal(program, buffer);
1997 if (result) {
1998 *out = buffer.str();
1999 }
2000 return result;
2001}
2002
Greg Daniela28ea672020-09-25 11:12:56 -04002003#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002004bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002005 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002006 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002007 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04002008 return result;
2009}
2010
Ethan Nicholas00543112018-07-31 09:44:36 -04002011bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002012 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002013 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002014 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002015 return result;
2016}
Greg Daniela28ea672020-09-25 11:12:56 -04002017#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002018
Ethan Nicholas2a479a52020-08-18 16:29:45 -04002019#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04002020
2021#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04002022bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04002023 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04002024 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05002025 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04002026 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002027 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05002028 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04002029 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04002030 return result;
2031}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04002032#endif
2033
Brian Osman401a0092020-09-10 14:47:24 -04002034const char* Compiler::OperatorName(Token::Kind op) {
2035 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002036 case Token::Kind::TK_PLUS: return "+";
2037 case Token::Kind::TK_MINUS: return "-";
2038 case Token::Kind::TK_STAR: return "*";
2039 case Token::Kind::TK_SLASH: return "/";
2040 case Token::Kind::TK_PERCENT: return "%";
2041 case Token::Kind::TK_SHL: return "<<";
2042 case Token::Kind::TK_SHR: return ">>";
2043 case Token::Kind::TK_LOGICALNOT: return "!";
2044 case Token::Kind::TK_LOGICALAND: return "&&";
2045 case Token::Kind::TK_LOGICALOR: return "||";
2046 case Token::Kind::TK_LOGICALXOR: return "^^";
2047 case Token::Kind::TK_BITWISENOT: return "~";
2048 case Token::Kind::TK_BITWISEAND: return "&";
2049 case Token::Kind::TK_BITWISEOR: return "|";
2050 case Token::Kind::TK_BITWISEXOR: return "^";
2051 case Token::Kind::TK_EQ: return "=";
2052 case Token::Kind::TK_EQEQ: return "==";
2053 case Token::Kind::TK_NEQ: return "!=";
2054 case Token::Kind::TK_LT: return "<";
2055 case Token::Kind::TK_GT: return ">";
2056 case Token::Kind::TK_LTEQ: return "<=";
2057 case Token::Kind::TK_GTEQ: return ">=";
2058 case Token::Kind::TK_PLUSEQ: return "+=";
2059 case Token::Kind::TK_MINUSEQ: return "-=";
2060 case Token::Kind::TK_STAREQ: return "*=";
2061 case Token::Kind::TK_SLASHEQ: return "/=";
2062 case Token::Kind::TK_PERCENTEQ: return "%=";
2063 case Token::Kind::TK_SHLEQ: return "<<=";
2064 case Token::Kind::TK_SHREQ: return ">>=";
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002065 case Token::Kind::TK_BITWISEANDEQ: return "&=";
2066 case Token::Kind::TK_BITWISEOREQ: return "|=";
2067 case Token::Kind::TK_BITWISEXOREQ: return "^=";
2068 case Token::Kind::TK_PLUSPLUS: return "++";
2069 case Token::Kind::TK_MINUSMINUS: return "--";
2070 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002071 default:
Brian Osman401a0092020-09-10 14:47:24 -04002072 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002073 }
2074}
2075
2076
2077bool Compiler::IsAssignment(Token::Kind op) {
2078 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002079 case Token::Kind::TK_EQ: // fall through
2080 case Token::Kind::TK_PLUSEQ: // fall through
2081 case Token::Kind::TK_MINUSEQ: // fall through
2082 case Token::Kind::TK_STAREQ: // fall through
2083 case Token::Kind::TK_SLASHEQ: // fall through
2084 case Token::Kind::TK_PERCENTEQ: // fall through
2085 case Token::Kind::TK_SHLEQ: // fall through
2086 case Token::Kind::TK_SHREQ: // fall through
2087 case Token::Kind::TK_BITWISEOREQ: // fall through
2088 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05002089 case Token::Kind::TK_BITWISEANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002090 return true;
2091 default:
2092 return false;
2093 }
2094}
2095
Brian Osman401a0092020-09-10 14:47:24 -04002096Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
2097 switch (op) {
2098 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
2099 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
2100 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
2101 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
2102 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
2103 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
2104 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
2105 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
2106 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
2107 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
Brian Osman401a0092020-09-10 14:47:24 -04002108 default: return op;
2109 }
2110}
2111
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002112Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05002113 if (fSource && offset >= 0) {
2114 int line = 1;
2115 int column = 1;
2116 for (int i = 0; i < offset; i++) {
2117 if ((*fSource)[i] == '\n') {
2118 ++line;
2119 column = 1;
2120 }
2121 else {
2122 ++column;
2123 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002124 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05002125 return Position(line, column);
2126 } else {
2127 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002128 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002129}
2130
2131void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002132 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002133 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05002134 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05002135 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07002136}
2137
John Stiles8d3642e2021-01-22 09:50:04 -05002138void Compiler::setErrorCount(int c) {
2139 if (c < fErrorCount) {
2140 fErrorText.resize(fErrorTextLength[c]);
2141 fErrorTextLength.resize(c);
2142 fErrorCount = c;
2143 }
2144}
2145
Ethan Nicholas95046142021-01-07 10:57:27 -05002146String Compiler::errorText(bool showCount) {
2147 if (showCount) {
2148 this->writeErrorCount();
2149 }
Ethan Nicholas00543112018-07-31 09:44:36 -04002150 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002151 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05002152 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07002153 return result;
2154}
2155
2156void Compiler::writeErrorCount() {
2157 if (fErrorCount) {
2158 fErrorText += to_string(fErrorCount) + " error";
2159 if (fErrorCount > 1) {
2160 fErrorText += "s";
2161 }
2162 fErrorText += "\n";
2163 }
2164}
2165
John Stilesa6841be2020-08-06 14:11:56 -04002166} // namespace SkSL