blob: 9e34016c23c94ff4859783cce7d551f0d0e779f7 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stilesb92641c2020-08-31 18:09:01 -040013#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/sksl/SkSLByteCodeGenerator.h"
15#include "src/sksl/SkSLCFGGenerator.h"
16#include "src/sksl/SkSLCPPCodeGenerator.h"
17#include "src/sksl/SkSLGLSLCodeGenerator.h"
18#include "src/sksl/SkSLHCodeGenerator.h"
19#include "src/sksl/SkSLIRGenerator.h"
20#include "src/sksl/SkSLMetalCodeGenerator.h"
21#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040022#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050024#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/ir/SkSLEnum.h"
26#include "src/sksl/ir/SkSLExpression.h"
27#include "src/sksl/ir/SkSLExpressionStatement.h"
28#include "src/sksl/ir/SkSLFunctionCall.h"
29#include "src/sksl/ir/SkSLIntLiteral.h"
30#include "src/sksl/ir/SkSLModifiersDeclaration.h"
31#include "src/sksl/ir/SkSLNop.h"
32#include "src/sksl/ir/SkSLSymbolTable.h"
33#include "src/sksl/ir/SkSLTernaryExpression.h"
34#include "src/sksl/ir/SkSLUnresolvedFunction.h"
35#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040036#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070037
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040038#include <fstream>
39
Ethan Nicholasa11035b2019-11-26 16:27:47 -050040#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
41#include "include/gpu/GrContextOptions.h"
42#include "src/gpu/GrShaderCaps.h"
43#endif
44
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040045#ifdef SK_ENABLE_SPIRV_VALIDATION
46#include "spirv-tools/libspirv.hpp"
47#endif
48
Brian Osman3d87e9f2020-10-08 11:50:22 -040049#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040050
Brian Osman3d87e9f2020-10-08 11:50:22 -040051// In standalone mode, we load the textual sksl source files. GN generates or copies these files
52// to the skslc executable directory. The "data" in this mode is just the filename.
53#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
54
55#else
56
57// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040058#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
59#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
60#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
61#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
62#include "src/sksl/generated/sksl_interp.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050063#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050064#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040065#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
66
Brian Osman3d87e9f2020-10-08 11:50:22 -040067#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
68 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040069
70#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040071
ethannicholasb3058bd2016-07-01 08:22:01 -070072namespace SkSL {
73
Brian Osman88cda172020-10-09 12:05:16 -040074class AutoSource {
75public:
76 AutoSource(Compiler* compiler, const String* source)
77 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
78 fCompiler->fSource = source;
79 }
80
81 ~AutoSource() { fCompiler->fSource = fOldSource; }
82
83 Compiler* fCompiler;
84 const String* fOldSource;
85};
86
Brian Osmand7e76592020-11-02 12:26:22 -050087Compiler::Compiler(const ShaderCapsClass* caps, Flags flags)
Brian Osman0006ad02020-11-18 15:38:39 -050088 : fContext(std::make_shared<Context>())
89 , fCaps(caps)
John Stiles7b920442020-12-17 10:43:41 -050090 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -050091 , fFlags(flags)
92 , fErrorCount(0) {
93 SkASSERT(fCaps);
John Stiles7c3515b2020-10-16 18:38:39 -040094 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050095 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stiles0f464502020-11-20 12:52:22 -050096 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), fCaps, *this);
ethannicholasb3058bd2016-07-01 08:22:01 -070097
Brian Osmanb06301e2020-11-06 11:45:36 -050098#define TYPE(t) fContext->f##t##_Type.get()
ethannicholasb3058bd2016-07-01 08:22:01 -070099
Brian Osmanb06301e2020-11-06 11:45:36 -0500100 const SkSL::Symbol* rootTypes[] = {
101 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500102
Brian Osmanb06301e2020-11-06 11:45:36 -0500103 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
104 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
105 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500106 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500107
Brian Osmanc0f2b642020-12-22 13:35:55 -0500108 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500109 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500110
Brian Osmanc63f4312020-12-23 11:44:14 -0500111 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700112
Brian Osman20fad322020-12-23 12:42:33 -0500113 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
114 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500115
116 TYPE(FragmentProcessor),
117 };
118
119 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500120 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
121 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
122 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
123 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
124 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
125
126 TYPE(GenUType), TYPE(UVec),
127 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
128
Brian Osmanc0f2b642020-12-22 13:35:55 -0500129 TYPE(Float2x3), TYPE(Float2x4),
130 TYPE(Float3x2), TYPE(Float3x4),
131 TYPE(Float4x2), TYPE(Float4x3),
132
Brian Osmanc63f4312020-12-23 11:44:14 -0500133 TYPE(Half2x3), TYPE(Half2x4),
134 TYPE(Half3x2), TYPE(Half3x4),
135 TYPE(Half4x2), TYPE(Half4x3),
136
Brian Osmanc0f2b642020-12-22 13:35:55 -0500137 TYPE(Mat), TYPE(HMat),
138
Brian Osmanb06301e2020-11-06 11:45:36 -0500139 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
140 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500141 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500142
143 TYPE(ISampler2D),
144 TYPE(Image2D), TYPE(IImage2D),
145 TYPE(SubpassInput), TYPE(SubpassInputMS),
146
Brian Osmanb06301e2020-11-06 11:45:36 -0500147 TYPE(Sampler),
148 TYPE(Texture2D),
149 };
150
151 for (const SkSL::Symbol* type : rootTypes) {
152 fRootSymbolTable->addWithoutOwnership(type);
153 }
154 for (const SkSL::Symbol* type : privateTypes) {
155 fPrivateSymbolTable->addWithoutOwnership(type);
156 }
157
158#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700159
Brian Osman3887a012020-09-30 13:22:27 -0400160 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
161 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500162 fPrivateSymbolTable->add(
163 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500164 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500165 "sk_Caps",
166 fContext->fSkCaps_Type.get(),
167 /*builtin=*/false,
168 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500169
Brian Osman3d87e9f2020-10-08 11:50:22 -0400170 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500171 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700172}
173
John Stilesdd13dba2020-10-29 10:45:34 -0400174Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700175
Brian Osman56269982020-11-20 12:38:07 -0500176const ParsedModule& Compiler::loadGPUModule() {
177 if (!fGPUModule.fSymbols) {
178 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
179 }
180 return fGPUModule;
181}
182
183const ParsedModule& Compiler::loadFragmentModule() {
184 if (!fFragmentModule.fSymbols) {
185 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag),
186 this->loadGPUModule());
187 }
188 return fFragmentModule;
189}
190
191const ParsedModule& Compiler::loadVertexModule() {
192 if (!fVertexModule.fSymbols) {
193 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert),
194 this->loadGPUModule());
195 }
196 return fVertexModule;
197}
198
Brian Osman88cda172020-10-09 12:05:16 -0400199const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400200 if (!fGeometryModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500201 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom),
202 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400203 }
Brian Osman88cda172020-10-09 12:05:16 -0400204 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400205}
206
Brian Osman88cda172020-10-09 12:05:16 -0400207const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400208 if (!fFPModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500209 fFPModule = this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp),
210 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400211 }
Brian Osman88cda172020-10-09 12:05:16 -0400212 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400213}
214
Brian Osmanb06301e2020-11-06 11:45:36 -0500215const ParsedModule& Compiler::loadPublicModule() {
216 if (!fPublicModule.fSymbols) {
217 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
218 }
219 return fPublicModule;
220}
221
Brian Osman91946752020-12-21 13:20:40 -0500222const ParsedModule& Compiler::loadRuntimeEffectModule() {
223 if (!fRuntimeEffectModule.fSymbols) {
224 fRuntimeEffectModule = this->parseModule(Program::kRuntimeEffect_Kind, MODULE_DATA(runtime),
225 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400226
Brian Osman91946752020-12-21 13:20:40 -0500227 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
228 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fFragmentProcessor_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400229
Brian Osman91946752020-12-21 13:20:40 -0500230 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fFloat2_Type.get());
231 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fFloat3_Type.get());
232 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fFloat4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400233
Brian Osman91946752020-12-21 13:20:40 -0500234 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fBool2_Type.get());
235 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fBool3_Type.get());
236 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fBool4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400237
Brian Osman91946752020-12-21 13:20:40 -0500238 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fFloat2x2_Type.get());
239 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fFloat3x3_Type.get());
240 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fFloat4x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400241
Brian Osman91946752020-12-21 13:20:40 -0500242 fRuntimeEffectModule.fSymbols->addAlias("mat2x2", fContext->fFloat2x2_Type.get());
243 fRuntimeEffectModule.fSymbols->addAlias("mat2x3", fContext->fFloat2x3_Type.get());
244 fRuntimeEffectModule.fSymbols->addAlias("mat2x4", fContext->fFloat2x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400245
Brian Osman91946752020-12-21 13:20:40 -0500246 fRuntimeEffectModule.fSymbols->addAlias("mat3x2", fContext->fFloat3x2_Type.get());
247 fRuntimeEffectModule.fSymbols->addAlias("mat3x3", fContext->fFloat3x3_Type.get());
248 fRuntimeEffectModule.fSymbols->addAlias("mat3x4", fContext->fFloat3x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400249
Brian Osman91946752020-12-21 13:20:40 -0500250 fRuntimeEffectModule.fSymbols->addAlias("mat4x2", fContext->fFloat4x2_Type.get());
251 fRuntimeEffectModule.fSymbols->addAlias("mat4x3", fContext->fFloat4x3_Type.get());
252 fRuntimeEffectModule.fSymbols->addAlias("mat4x4", fContext->fFloat4x4_Type.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400253 }
Brian Osman91946752020-12-21 13:20:40 -0500254 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400255}
256
Brian Osman88cda172020-10-09 12:05:16 -0400257const ParsedModule& Compiler::loadInterpreterModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400258 if (!fInterpreterModule.fSymbols) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500259 fInterpreterModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(interp),
260 this->loadPublicModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400261 }
Brian Osman88cda172020-10-09 12:05:16 -0400262 return fInterpreterModule;
263}
264
265const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
266 switch (kind) {
Brian Osman91946752020-12-21 13:20:40 -0500267 case Program::kVertex_Kind: return this->loadVertexModule(); break;
268 case Program::kFragment_Kind: return this->loadFragmentModule(); break;
269 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
270 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
271 case Program::kRuntimeEffect_Kind: return this->loadRuntimeEffectModule(); break;
272 case Program::kGeneric_Kind: return this->loadInterpreterModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400273 }
274 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400275}
276
Brian Osman3d87e9f2020-10-08 11:50:22 -0400277LoadedModule Compiler::loadModule(Program::Kind kind,
278 ModuleData data,
279 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400280 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500281 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
282 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
283 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
284 // like samplers or textures. Today, 'Private' does contain the union of all known types,
285 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
286 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
287 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400288 }
289
290#if defined(SKSL_STANDALONE)
291 SkASSERT(data.fPath);
292 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400293 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
294 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400295 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400296 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400297 abort();
298 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400299 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400300 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400301 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400302 SkASSERT(fIRGenerator->fCanInline);
303 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400304 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500305 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500306 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500307 /*isBuiltinCode=*/true, source->c_str(), source->length(),
308 /*externalValues=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400309 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500310 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400311 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400312 if (this->fErrorCount) {
313 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400314 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400315 }
Brian Osman88cda172020-10-09 12:05:16 -0400316 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400317#else
318 SkASSERT(data.fData && (data.fSize != 0));
319 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
320 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500321 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400322 fModifiers.push_back(fIRGenerator->releaseModifiers());
323#endif
324
325 return module;
326}
327
328ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500329 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
330 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400331
332 // For modules that just declare (but don't define) intrinsic functions, there will be no new
333 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500334 if (module.fElements.empty()) {
335 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400336 }
337
338 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
339
340 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
341 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500342 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400343 switch (element->kind()) {
344 case ProgramElement::Kind::kFunction: {
345 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400346 SkASSERT(f.declaration().isBuiltin());
347 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400348 break;
349 }
John Stiles569249b2020-11-03 12:18:22 -0500350 case ProgramElement::Kind::kFunctionPrototype: {
351 // These are already in the symbol table.
352 break;
353 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400354 case ProgramElement::Kind::kEnum: {
355 const Enum& e = element->as<Enum>();
356 SkASSERT(e.isBuiltin());
357 intrinsics->insertOrDie(e.typeName(), std::move(element));
358 break;
359 }
360 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400361 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
362 const Variable& var = global.declaration()->as<VarDeclaration>().var();
363 SkASSERT(var.isBuiltin());
364 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400365 break;
366 }
367 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400368 const Variable& var = element->as<InterfaceBlock>().variable();
369 SkASSERT(var.isBuiltin());
370 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400371 break;
372 }
373 default:
374 printf("Unsupported element: %s\n", element->description().c_str());
375 SkASSERT(false);
376 break;
377 }
378 }
379
Brian Osman0006ad02020-11-18 15:38:39 -0500380 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400381}
382
ethannicholas22f939e2016-10-13 13:25:34 -0700383// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500384void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
385 DefinitionMap* definitions) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400386 switch (lvalue->kind()) {
387 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -0400388 const Variable& var = *lvalue->as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400389 if (var.storage() == Variable::Storage::kLocal) {
John Stiles796cdb72020-10-08 12:06:53 -0400390 definitions->set(&var, expr);
ethannicholas22f939e2016-10-13 13:25:34 -0700391 }
392 break;
393 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400394 case Expression::Kind::kSwizzle:
ethannicholas22f939e2016-10-13 13:25:34 -0700395 // We consider the variable written to as long as at least some of its components have
396 // been written to. This will lead to some false negatives (we won't catch it if you
397 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400398 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
399 // 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 -0700400 // more complicated whole-program analysis. This is probably good enough.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400401 this->addDefinition(lvalue->as<Swizzle>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400402 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700403 definitions);
404 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400405 case Expression::Kind::kIndex:
ethannicholas22f939e2016-10-13 13:25:34 -0700406 // see comments in Swizzle
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400407 this->addDefinition(lvalue->as<IndexExpression>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400408 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700409 definitions);
410 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400411 case Expression::Kind::kFieldAccess:
ethannicholas22f939e2016-10-13 13:25:34 -0700412 // see comments in Swizzle
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400413 this->addDefinition(lvalue->as<FieldAccess>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400414 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700415 definitions);
416 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400417 case Expression::Kind::kTernary:
Ethan Nicholasa583b812018-01-18 13:32:11 -0500418 // To simplify analysis, we just pretend that we write to both sides of the ternary.
419 // This allows for false positives (meaning we fail to detect that a variable might not
420 // have been assigned), but is preferable to false negatives.
Ethan Nicholasdd218162020-10-08 05:48:01 -0400421 this->addDefinition(lvalue->as<TernaryExpression>().ifTrue().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400422 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500423 definitions);
Ethan Nicholasdd218162020-10-08 05:48:01 -0400424 this->addDefinition(lvalue->as<TernaryExpression>().ifFalse().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400425 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500426 definitions);
427 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400428 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400429 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700430 default:
431 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400432 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700433 }
434}
435
436// add local variables defined by this node to the set
John Stiles796cdb72020-10-08 12:06:53 -0400437void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) {
John Stiles70025e52020-09-28 16:08:58 -0400438 if (node.isExpression()) {
439 Expression* expr = node.expression()->get();
440 switch (expr->kind()) {
441 case Expression::Kind::kBinary: {
442 BinaryExpression* b = &expr->as<BinaryExpression>();
443 if (b->getOperator() == Token::Kind::TK_EQ) {
John Stiles2d4f9592020-10-30 10:29:12 -0400444 this->addDefinition(b->left().get(), &b->right(), definitions);
John Stiles70025e52020-09-28 16:08:58 -0400445 } else if (Compiler::IsAssignment(b->getOperator())) {
446 this->addDefinition(
John Stiles2d4f9592020-10-30 10:29:12 -0400447 b->left().get(),
John Stiles70025e52020-09-28 16:08:58 -0400448 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
449 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500450
ethannicholas22f939e2016-10-13 13:25:34 -0700451 }
John Stiles70025e52020-09-28 16:08:58 -0400452 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700453 }
John Stiles70025e52020-09-28 16:08:58 -0400454 case Expression::Kind::kFunctionCall: {
455 const FunctionCall& c = expr->as<FunctionCall>();
Brian Osman5bf3e202020-10-13 10:34:18 -0400456 const std::vector<const Variable*>& parameters = c.function().parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400457 for (size_t i = 0; i < parameters.size(); ++i) {
458 if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stiles70025e52020-09-28 16:08:58 -0400459 this->addDefinition(
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400460 c.arguments()[i].get(),
John Stiles70025e52020-09-28 16:08:58 -0400461 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
462 definitions);
463 }
464 }
465 break;
466 }
467 case Expression::Kind::kPrefix: {
468 const PrefixExpression* p = &expr->as<PrefixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400469 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
470 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400471 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400472 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400473 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
474 definitions);
475 }
476 break;
477 }
478 case Expression::Kind::kPostfix: {
479 const PostfixExpression* p = &expr->as<PostfixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400480 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
481 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400482 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400483 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400484 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
485 definitions);
486 }
487 break;
488 }
489 case Expression::Kind::kVariableReference: {
490 const VariableReference* v = &expr->as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400491 if (v->refKind() != VariableReference::RefKind::kRead) {
John Stiles70025e52020-09-28 16:08:58 -0400492 this->addDefinition(
493 v,
494 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
495 definitions);
496 }
497 break;
498 }
499 default:
500 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700501 }
John Stiles70025e52020-09-28 16:08:58 -0400502 } else if (node.isStatement()) {
503 Statement* stmt = node.statement()->get();
504 if (stmt->is<VarDeclaration>()) {
505 VarDeclaration& vd = stmt->as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400506 if (vd.value()) {
507 definitions->set(&vd.var(), &vd.value());
ethannicholas22f939e2016-10-13 13:25:34 -0700508 }
ethannicholas22f939e2016-10-13 13:25:34 -0700509 }
510 }
511}
512
John Stilese6150002020-10-05 12:03:53 -0400513void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700514 BasicBlock& block = cfg->fBlocks[blockId];
515
516 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500517 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700518 for (const BasicBlock::Node& n : block.fNodes) {
519 this->addDefinitions(n, &after);
520 }
521
522 // propagate definitions to exits
523 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400524 if (exitId == blockId) {
525 continue;
526 }
ethannicholas22f939e2016-10-13 13:25:34 -0700527 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500528 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400529 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
530 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400531 // exit has no definition for it, just copy it and reprocess exit block
532 processedSet->reset(exitId);
John Stiles796cdb72020-10-08 12:06:53 -0400533 exit.fBefore[var] = e1;
ethannicholas22f939e2016-10-13 13:25:34 -0700534 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500535 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400536 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700537 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400538 // definition has changed, merge and reprocess the exit block
539 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500540 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400541 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500542 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400543 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500544 }
ethannicholas22f939e2016-10-13 13:25:34 -0700545 }
546 }
John Stiles65b48272020-12-22 17:18:34 -0500547 }
ethannicholas22f939e2016-10-13 13:25:34 -0700548 }
549}
550
551// returns a map which maps all local variables in the function to null, indicating that their value
552// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500553static DefinitionMap compute_start_state(const CFG& cfg) {
554 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400555 for (const auto& block : cfg.fBlocks) {
556 for (const auto& node : block.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -0400557 if (node.isStatement()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400558 const Statement* s = node.statement()->get();
Brian Osmanc0213602020-10-06 14:43:32 -0400559 if (s->is<VarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400560 result[&s->as<VarDeclaration>().var()] = nullptr;
ethannicholas22f939e2016-10-13 13:25:34 -0700561 }
562 }
563 }
564 }
565 return result;
566}
567
Ethan Nicholascb670962017-04-20 19:31:52 -0400568/**
569 * Returns true if assigning to this lvalue has no effect.
570 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400571static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400572 switch (lvalue.kind()) {
573 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400574 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400575 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400576 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400577 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400578 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400579 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400580 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400581 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400582 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400583 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400584 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400585 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400586 return !t.test()->hasSideEffects() &&
587 is_dead(*t.ifTrue(), usage) &&
588 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500589 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400590 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400591 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400592 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500593#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400594 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500595#endif
596 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400597 }
598}
ethannicholas22f939e2016-10-13 13:25:34 -0700599
Ethan Nicholascb670962017-04-20 19:31:52 -0400600/**
601 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
602 * to a dead target and lack of side effects on the left hand side.
603 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400604static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400605 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400606 return false;
607 }
John Stiles2d4f9592020-10-30 10:29:12 -0400608 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400609}
610
611void Compiler::computeDataFlow(CFG* cfg) {
612 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400613
614 // We set bits in the "processed" set after a block has been scanned.
615 SkBitSet processedSet(cfg->fBlocks.size());
616 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
617 processedSet.set(*blockId);
618 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700619 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400620}
621
622/**
623 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
624 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
625 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
626 * need to be regenerated).
627 */
John Stilesafbf8992020-08-18 10:08:21 -0400628static bool try_replace_expression(BasicBlock* b,
629 std::vector<BasicBlock::Node>::iterator* iter,
630 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400631 std::unique_ptr<Expression>* target = (*iter)->expression();
632 if (!b->tryRemoveExpression(iter)) {
633 *target = std::move(*newExpression);
634 return false;
635 }
636 *target = std::move(*newExpression);
637 return b->tryInsertExpression(iter, target);
638}
639
640/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400641 * Returns true if the expression is a constant numeric literal with the specified value, or a
642 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400643 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400644template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400645static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400646 switch (expr.kind()) {
647 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400648 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400649
Ethan Nicholase6592142020-09-08 10:22:09 -0400650 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400651 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400652
Ethan Nicholase6592142020-09-08 10:22:09 -0400653 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400654 const Constructor& constructor = expr.as<Constructor>();
655 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400656 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400657 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400658 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500659 if (constructor.componentType().isFloat()) {
660 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400661 if (constructor.getFVecComponent(i) != value) {
662 return false;
663 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500664 }
665 return true;
666 } else if (constructor.componentType().isInteger()) {
667 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400668 if (constructor.getIVecComponent(i) != value) {
669 return false;
670 }
671 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500672 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400673 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500674 // Other types (e.g. boolean) might occur, but aren't supported here.
675 return false;
John Stiles9d944232020-08-19 09:56:49 -0400676
Ethan Nicholase6592142020-09-08 10:22:09 -0400677 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400678 SkASSERT(constructor.arguments().size() == 1);
679 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400680
681 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400682 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400683 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400684 }
685 return false;
686 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400687 default:
688 return false;
689 }
690}
691
692/**
693 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
694 * and CFG structures).
695 */
John Stilesafbf8992020-08-18 10:08:21 -0400696static void delete_left(BasicBlock* b,
697 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400698 Compiler::OptimizationContext* optimizationContext) {
699 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400700 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400701 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400702 Expression& left = *bin.left();
703 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400704 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400705 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400706 if (bin.getOperator() == Token::Kind::TK_EQ) {
707 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400708 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400709 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400710 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400711 // Remove references within LHS.
712 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400713 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400714 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400715 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400716 return;
717 }
718 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400719 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400720 return;
721 }
722 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400723 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400724 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400725 return;
726 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400727 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400728 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400729}
730
731/**
732 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
733 * CFG structures).
734 */
John Stilesafbf8992020-08-18 10:08:21 -0400735static void delete_right(BasicBlock* b,
736 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400737 Compiler::OptimizationContext* optimizationContext) {
738 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400739 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400740 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400741 std::unique_ptr<Expression>& leftPointer = bin.left();
742 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400743 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400744 // Remove references within RHS.
745 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400746 if (!b->tryRemoveExpressionBefore(iter, &right)) {
747 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400748 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400749 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400750 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400751 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400752 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400753 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400754 return;
755 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400756 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400757 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400758 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400759 return;
760 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400761 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400762 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400763}
764
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400765/**
766 * Constructs the specified type using a single argument.
767 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400768static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400769 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400770 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400771 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400772 return result;
773}
774
775/**
776 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
777 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
778 */
779static void vectorize(BasicBlock* b,
780 std::vector<BasicBlock::Node>::iterator* iter,
781 const Type& type,
782 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400783 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400784 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500785 SkASSERT(type.isVector());
786 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400787 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400788 std::unique_ptr<Expression>* target = (*iter)->expression();
789 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400790 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400791 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400792 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400793 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400794 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400795 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400796 }
797 }
798}
799
800/**
801 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
802 * left to yield vec<n>(x).
803 */
804static void vectorize_left(BasicBlock* b,
805 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400806 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400807 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400808 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400809 optimizationContext->fUsage->remove(bin.right().get());
810 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400811}
812
813/**
814 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
815 * right to yield vec<n>(y).
816 */
817static void vectorize_right(BasicBlock* b,
818 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400819 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400820 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400821 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400822 optimizationContext->fUsage->remove(bin.left().get());
823 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400824}
825
826// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400827static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400828 switch (expr.kind()) {
829 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400830 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400831 break;
832 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400833 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400834 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400835 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400836 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400837 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400838 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400839 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400840 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400841 break;
842 default:
843 ABORT("shouldn't be writing to this kind of expression\n");
844 break;
845 }
846}
847
Ethan Nicholascb670962017-04-20 19:31:52 -0400848void Compiler::simplifyExpression(DefinitionMap& definitions,
849 BasicBlock& b,
850 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400851 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400852 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400853 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500854
Ethan Nicholascb670962017-04-20 19:31:52 -0400855 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400856 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
857 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400858 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400859 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400860 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400861 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400862 // Remove references within 'expr', add references within 'optimized'
863 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400864 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400865 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400866 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400867 }
John Stiles70025e52020-09-28 16:08:58 -0400868 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400869 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400870 }
871 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400872 switch (expr->kind()) {
873 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400874 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400875 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400876 if (ref.refKind() != VariableReference::RefKind::kWrite &&
877 ref.refKind() != VariableReference::RefKind::kPointer &&
878 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400879 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
880 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000881 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400882 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400883 }
884 break;
885 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400886 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400887 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400888 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400889 // ternary has a constant test, replace it with either the true or
890 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400891 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400892 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400893 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400894 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400895 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400896 optimizationContext->fUpdated = true;
897 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400898 }
899 break;
900 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400901 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400902 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400903 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400904 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400905 break;
906 }
John Stiles2d4f9592020-10-30 10:29:12 -0400907 Expression& left = *bin->left();
908 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400909 const Type& leftType = left.type();
910 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400911 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500912 if ((!leftType.isScalar() && !leftType.isVector()) ||
913 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400914 break;
915 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400916 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400917 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400918 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500919 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400920 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400921 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400922 } else {
923 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400924 // 1 * float4(x) -> float4(x)
925 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400926 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400927 }
928 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400929 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500930 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400931 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400932 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400933 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400934 } else {
935 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400936 // float4(0) * x -> float4(0)
937 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400938 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400939 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500940 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400941 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400942 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400943 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500944 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400945 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400946 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400947 } else {
948 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400949 // float4(x) * 1 -> float4(x)
950 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400951 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400952 }
953 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400954 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500955 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400956 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400957 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400958 } else {
959 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400960 // x * float4(0) -> float4(0)
961 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400962 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400963 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500964 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400965 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400966 }
967 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400968 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400969 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500970 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400971 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400972 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400973 } else {
974 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400975 // 0 + float4(x) -> float4(x)
976 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400977 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400978 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400979 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500980 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400981 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400982 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400983 } else {
984 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400985 // float4(x) + 0 -> float4(x)
986 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400987 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400988 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400989 }
990 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400991 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400992 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500993 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400994 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400995 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400996 } else {
997 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400998 // float4(x) - 0 -> float4(x)
999 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001000 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001001 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001002 }
1003 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001004 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001005 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -05001006 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001007 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001008 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001009 } else {
1010 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001011 // float4(x) / 1 -> float4(x)
1012 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001013 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001014 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001015 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -05001016 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001017 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001018 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001019 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001020 } else {
1021 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001022 // float4(0) / x -> float4(0)
1023 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001024 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001025 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001026 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001027 }
1028 }
1029 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001030 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001031 if (is_constant(right, 0)) {
1032 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001033 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001034 }
1035 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001036 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001037 if (is_constant(right, 0)) {
1038 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001039 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001040 }
1041 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001042 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001043 if (is_constant(right, 1)) {
1044 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001045 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001046 }
1047 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001048 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001049 if (is_constant(right, 1)) {
1050 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001051 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001052 }
1053 break;
1054 default:
1055 break;
1056 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001057 break;
1058 }
John Stilesf5c1d042020-11-21 23:26:07 -05001059 case Expression::Kind::kConstructor: {
1060 // Find constructors embedded inside constructors and flatten them out where possible.
1061 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
1062 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
1063 // Leave single-argument constructors alone, though. These might be casts or splats.
1064 Constructor& c = expr->as<Constructor>();
1065 if (c.type().columns() > 1) {
1066 // Inspect each constructor argument to see if it's a candidate for flattening.
1067 // Remember matched arguments in a bitfield, "argsToOptimize".
1068 int argsToOptimize = 0;
1069 int currBit = 1;
1070 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1071 if (arg->is<Constructor>()) {
1072 Constructor& inner = arg->as<Constructor>();
1073 if (inner.arguments().size() > 1 &&
1074 inner.type().componentType() == c.type().componentType()) {
1075 argsToOptimize |= currBit;
1076 }
1077 }
1078 currBit <<= 1;
1079 }
1080 if (argsToOptimize) {
1081 // We found at least one argument that could be flattened out. Re-walk the
1082 // constructor args and flatten the candidates we found during our initial pass.
1083 ExpressionArray flattened;
1084 flattened.reserve_back(c.type().columns());
1085 currBit = 1;
1086 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1087 if (argsToOptimize & currBit) {
1088 Constructor& inner = arg->as<Constructor>();
1089 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
1090 flattened.push_back(innerArg->clone());
1091 }
1092 } else {
1093 flattened.push_back(arg->clone());
1094 }
1095 currBit <<= 1;
1096 }
1097 auto optimized = std::unique_ptr<Expression>(
1098 new Constructor(c.fOffset, &c.type(), std::move(flattened)));
1099 // No fUsage change; no references have been added or removed anywhere.
1100 optimizationContext->fUpdated = true;
1101 if (!try_replace_expression(&b, iter, &optimized)) {
1102 optimizationContext->fNeedsRescan = true;
1103 return;
1104 }
1105 SkASSERT((*iter)->isExpression());
1106 break;
1107 }
1108 }
1109 break;
1110 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001111 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001112 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -05001113 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001114 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001115 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001116 for (int i = 0; i < (int) s.components().size(); ++i) {
1117 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001118 identity = false;
1119 break;
1120 }
1121 }
1122 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001123 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001124 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001125 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001126 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001127 return;
1128 }
John Stiles70025e52020-09-28 16:08:58 -04001129 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001130 break;
1131 }
1132 }
John Stiles108bbe22020-11-18 11:10:38 -05001133 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1134 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001135 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001136 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001137 for (int c : s.components()) {
1138 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001139 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001140 optimizationContext->fUpdated = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001141 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001142 final));
John Stiles108bbe22020-11-18 11:10:38 -05001143 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001144 if (!try_replace_expression(&b, iter, &replacement)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001145 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001146 return;
1147 }
John Stiles70025e52020-09-28 16:08:58 -04001148 SkASSERT((*iter)->isExpression());
John Stiles108bbe22020-11-18 11:10:38 -05001149 break;
1150 }
1151 // Optimize swizzles of constructors.
1152 if (s.base()->is<Constructor>()) {
1153 Constructor& base = s.base()->as<Constructor>();
1154 std::unique_ptr<Expression> replacement;
1155 const Type& componentType = base.type().componentType();
1156 int swizzleSize = s.components().size();
1157
1158 // The IR generator has already converted any zero/one swizzle components into
1159 // constructors containing zero/one args. Confirm that this is true by checking that
1160 // our swizzle components are all `xyzw` (values 0 through 3).
1161 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1162 [](int8_t c) { return c >= 0 && c <= 3; }));
1163
John Stiles9aeed132020-11-24 17:36:06 -05001164 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001165 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1166 // components don't actually matter since all fields are the same.
1167 ExpressionArray newArgs;
1168 newArgs.push_back(base.arguments().front()->clone());
1169 replacement = std::make_unique<Constructor>(
1170 base.fOffset,
1171 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1172 std::move(newArgs));
1173
John Stilesa60ac0c2020-12-22 08:59:51 -05001174 // We're replacing an expression with a cloned version; we'll need a rescan.
1175 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1176 // reference counts.
1177 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001178 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001179 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001180 break;
1181 }
1182
John Stiles0777ac42020-11-19 11:06:47 -05001183 // Swizzles can duplicate some elements and discard others, e.g.
1184 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1185 // - Expressions with side effects need to occur exactly once, even if they
1186 // would otherwise be swizzle-eliminated
1187 // - Non-trivial expressions should not be repeated, but elimination is OK.
1188 //
1189 // Look up the argument for the constructor at each index. This is typically simple
1190 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1191 // seems. This example would result in:
1192 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1193 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1194 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1195 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1196 struct ConstructorArgMap {
1197 int8_t fArgIndex;
1198 int8_t fComponent;
1199 };
1200
1201 int numConstructorArgs = base.type().columns();
1202 ConstructorArgMap argMap[4] = {};
1203 int writeIdx = 0;
1204 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1205 const Expression& expr = *base.arguments()[argIdx];
1206 int argWidth = expr.type().columns();
1207 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1208 argMap[writeIdx].fArgIndex = argIdx;
1209 argMap[writeIdx].fComponent = componentIdx;
1210 ++writeIdx;
1211 }
1212 }
1213 SkASSERT(writeIdx == numConstructorArgs);
1214
1215 // Count up the number of times each constructor argument is used by the
1216 // swizzle.
1217 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1218 // - bar.yz is referenced 3 times, by `.x_xy`
1219 // - half(foo) is referenced 1 time, by `._w__`
1220 int8_t exprUsed[4] = {};
1221 for (int c : s.components()) {
1222 exprUsed[argMap[c].fArgIndex]++;
1223 }
1224
1225 bool safeToOptimize = true;
1226 for (int index = 0; index < numConstructorArgs; ++index) {
1227 int8_t constructorArgIndex = argMap[index].fArgIndex;
1228 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1229
1230 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001231 if (exprUsed[constructorArgIndex] > 1 &&
1232 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001233 safeToOptimize = false;
1234 break;
1235 }
1236 // Check that side-effect-bearing expressions are swizzled in exactly once.
1237 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1238 safeToOptimize = false;
1239 break;
1240 }
1241 }
1242
1243 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001244 struct ReorderedArgument {
1245 int8_t fArgIndex;
1246 ComponentArray fComponents;
1247 };
1248 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001249 for (int c : s.components()) {
1250 const ConstructorArgMap& argument = argMap[c];
1251 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1252
John Stiles9aeed132020-11-24 17:36:06 -05001253 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001254 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001255 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001256 reorderedArgs.push_back({argument.fArgIndex,
1257 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001258 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001259 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001260 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001261 if (reorderedArgs.empty() ||
1262 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1263 // This can't be combined with the previous argument. Add a new one.
1264 reorderedArgs.push_back({argument.fArgIndex,
1265 ComponentArray{argument.fComponent}});
1266 } else {
1267 // Since we know this argument uses components, it should already
1268 // have at least one component set.
1269 SkASSERT(!reorderedArgs.back().fComponents.empty());
1270 // Build up the current argument with one more component.
1271 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1272 }
John Stiles0777ac42020-11-19 11:06:47 -05001273 }
1274 }
John Stilesd9076cb2020-11-19 12:18:36 -05001275
1276 // Convert our reordered argument list to an actual array of expressions, with
1277 // the new order and any new inner swizzles that need to be applied. Note that
1278 // we expect followup passes to clean up the inner swizzles.
1279 ExpressionArray newArgs;
1280 newArgs.reserve_back(swizzleSize);
1281 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1282 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1283 if (reorderedArg.fComponents.empty()) {
1284 newArgs.push_back(baseArg.clone());
1285 } else {
1286 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1287 reorderedArg.fComponents));
1288 }
1289 }
1290
1291 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001292 replacement = std::make_unique<Constructor>(
1293 base.fOffset,
1294 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1295 std::move(newArgs));
1296
John Stilesa60ac0c2020-12-22 08:59:51 -05001297 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001298 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001299
1300 // We're replacing an expression with a cloned version; we'll need a rescan.
1301 try_replace_expression(&b, iter, &replacement);
1302 optimizationContext->fUpdated = true;
1303 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001304 }
John Stiles108bbe22020-11-18 11:10:38 -05001305 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001306 }
John Stiles30212b72020-06-11 17:55:07 -04001307 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001308 }
1309 default:
1310 break;
1311 }
1312}
1313
John Stiles92219b42020-06-15 12:32:24 -04001314// Returns true if this statement could potentially execute a break at the current level. We ignore
1315// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001316static bool contains_conditional_break(Statement& stmt) {
1317 class ContainsConditionalBreak : public ProgramVisitor {
1318 public:
1319 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001320 switch (stmt.kind()) {
1321 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001322 return this->INHERITED::visitStatement(stmt);
1323
Ethan Nicholase6592142020-09-08 10:22:09 -04001324 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001325 return fInConditional > 0;
1326
Ethan Nicholase6592142020-09-08 10:22:09 -04001327 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001328 ++fInConditional;
1329 bool result = this->INHERITED::visitStatement(stmt);
1330 --fInConditional;
1331 return result;
1332 }
1333
1334 default:
1335 return false;
1336 }
1337 }
1338
1339 int fInConditional = 0;
1340 using INHERITED = ProgramVisitor;
1341 };
1342
1343 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001344}
1345
Ethan Nicholas5005a222018-08-24 13:06:27 -04001346// returns true if this statement definitely executes a break at the current level (we ignore
1347// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001348static bool contains_unconditional_break(Statement& stmt) {
1349 class ContainsUnconditionalBreak : public ProgramVisitor {
1350 public:
1351 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001352 switch (stmt.kind()) {
1353 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001354 return this->INHERITED::visitStatement(stmt);
1355
Ethan Nicholase6592142020-09-08 10:22:09 -04001356 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001357 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001358
1359 default:
1360 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001361 }
John Stilesb92641c2020-08-31 18:09:01 -04001362 }
John Stiles92219b42020-06-15 12:32:24 -04001363
John Stilesb92641c2020-08-31 18:09:01 -04001364 using INHERITED = ProgramVisitor;
1365 };
John Stiles92219b42020-06-15 12:32:24 -04001366
John Stilesb92641c2020-08-31 18:09:01 -04001367 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001368}
1369
John Stiles8f2a0cf2020-10-13 12:48:21 -04001370static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001371 switch (stmt->kind()) {
1372 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001373 // Recurse into the block.
1374 Block& block = static_cast<Block&>(*stmt);
1375
John Stiles8f2a0cf2020-10-13 12:48:21 -04001376 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001377 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001378 for (std::unique_ptr<Statement>& stmt : block.children()) {
1379 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001380 }
John Stiles92219b42020-06-15 12:32:24 -04001381
1382 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001383 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001384 break;
John Stiles92219b42020-06-15 12:32:24 -04001385 }
1386
Ethan Nicholase6592142020-09-08 10:22:09 -04001387 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001388 // Do not append a break to the target.
1389 break;
1390
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001391 default:
John Stiles92219b42020-06-15 12:32:24 -04001392 // Append normal statements to the target.
1393 target->push_back(std::move(stmt));
1394 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001395 }
1396}
1397
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001398// Returns a block containing all of the statements that will be run if the given case matches
1399// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1400// broken by this call and must then be discarded).
1401// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1402// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001403static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1404 SwitchCase* caseToCapture) {
1405 // We have to be careful to not move any of the pointers until after we're sure we're going to
1406 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1407 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001408 auto iter = switchStatement->cases().begin();
1409 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001410 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001411 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001412 }
John Stiles92219b42020-06-15 12:32:24 -04001413 }
1414
1415 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1416 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1417 // statements that we can use for simplification.
1418 auto startIter = iter;
1419 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001420 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001421 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001422 if (contains_conditional_break(*stmt)) {
1423 // We can't reduce switch-cases to a block when they have conditional breaks.
1424 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001425 }
John Stiles92219b42020-06-15 12:32:24 -04001426
1427 if (contains_unconditional_break(*stmt)) {
1428 // We found an unconditional break. We can use this block, but we need to strip
1429 // out the break statement.
1430 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001431 break;
1432 }
1433 }
John Stiles92219b42020-06-15 12:32:24 -04001434
1435 if (unconditionalBreakStmt != nullptr) {
1436 break;
1437 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001438 }
John Stiles92219b42020-06-15 12:32:24 -04001439
1440 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1441 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001442 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001443
1444 // We can move over most of the statements as-is.
1445 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001446 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001447 caseStmts.push_back(std::move(stmt));
1448 }
1449 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001450 }
John Stiles92219b42020-06-15 12:32:24 -04001451
1452 // If we found an unconditional break at the end, we need to move what we can while avoiding
1453 // that break.
1454 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001455 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001456 if (stmt.get() == unconditionalBreakStmt) {
1457 move_all_but_break(stmt, &caseStmts);
1458 unconditionalBreakStmt = nullptr;
1459 break;
1460 }
1461
1462 caseStmts.push_back(std::move(stmt));
1463 }
1464 }
1465
1466 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1467
1468 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001469 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001470}
1471
Ethan Nicholascb670962017-04-20 19:31:52 -04001472void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001473 BasicBlock& b,
1474 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001475 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001476 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001477 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001478 switch (stmt->kind()) {
1479 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001480 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001481 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001482 (!varDecl.value() ||
1483 !varDecl.value()->hasSideEffects())) {
1484 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001485 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001486 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001487 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001488 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001489 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001490 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001491 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001492 }
1493 break;
1494 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001495 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001496 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001497 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001498 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001499 if (i.test()->as<BoolLiteral>().value()) {
1500 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001501 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001502 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001503 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001504 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001505 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001506 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001507 }
1508 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001509 optimizationContext->fUpdated = true;
1510 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001511 break;
1512 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001513 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001514 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001515 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001516 optimizationContext->fUpdated = true;
1517 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001518 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001519 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001520 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001521 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001522 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001523 (*iter)->setStatement(
1524 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001525 } else {
1526 // no if, no else, no test side effects, kill the whole if
1527 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001528 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001529 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001530 optimizationContext->fUpdated = true;
1531 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001532 }
1533 break;
1534 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001535 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001536 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001537 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001538 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001539 // switch is constant, replace it with the case that matches
1540 bool found = false;
1541 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001542 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1543 if (!c->value()) {
1544 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001545 continue;
1546 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001547 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001548 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001549 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001550 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001551 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001552 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001553 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001554 break;
1555 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001556 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1557 optimizationContext->fSilences.find(&s) ==
1558 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001559 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001560 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001561 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001562 }
1563 return; // can't simplify
1564 }
1565 }
1566 }
1567 if (!found) {
1568 // no matching case. use default if it exists, or kill the whole thing
1569 if (defaultCase) {
1570 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1571 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001572 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001573 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001574 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1575 optimizationContext->fSilences.find(&s) ==
1576 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001577 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001578 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001579 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001580 }
1581 return; // can't simplify
1582 }
1583 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001584 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001585 }
1586 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001587 optimizationContext->fUpdated = true;
1588 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001589 }
1590 break;
1591 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001592 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001593 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001594 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001595 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001596 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001597 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001598 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001599 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001600 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001601 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001602 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001603 }
1604 break;
1605 }
1606 default:
1607 break;
1608 }
1609}
1610
Brian Osman010ce6a2020-10-19 16:34:10 -04001611bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001612 bool madeChanges = false;
1613
Ethan Nicholascb670962017-04-20 19:31:52 -04001614 CFG cfg = CFGGenerator().getCFG(f);
1615 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001616
1617 // check for unreachable code
1618 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001619 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001620 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001621 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001622 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001623 if (node.isStatement()) {
1624 offset = (*node.statement())->fOffset;
1625 } else {
1626 offset = (*node.expression())->fOffset;
1627 if ((*node.expression())->is<BoolLiteral>()) {
1628 // Function inlining can generate do { ... } while(false) loops which always
1629 // break, so the boolean condition is considered unreachable. Since not being
1630 // able to reach a literal is a non-issue in the first place, we don't report an
1631 // error in this case.
1632 continue;
1633 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001634 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001635 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001636 }
1637 }
1638 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001639 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001640 }
1641
Ethan Nicholascb670962017-04-20 19:31:52 -04001642 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001643 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001644 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001645 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001646 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001647 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001648 cfg = CFGGenerator().getCFG(f);
1649 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001650 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001651 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001652
John Stiles7d3f0892020-11-03 11:35:01 -05001653 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001654 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001655
1656 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1657 if (eliminatedBlockIds.test(blockId)) {
1658 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1659 optimizationContext.fUpdated = true;
1660 optimizationContext.fNeedsRescan = true;
1661 break;
1662 }
1663
1664 BasicBlock& b = cfg.fBlocks[blockId];
1665 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001666 // Block was reachable before optimization, but has since become unreachable. In
1667 // addition to being dead code, it's broken - since control flow can't reach it, no
1668 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001669 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001670 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001671 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001672 // Eliminating a node runs the risk of eliminating that node's exits as
1673 // well. Keep track of this and do a rescan if we are about to access one
1674 // of these.
1675 for (BlockId id : b.fExits) {
1676 eliminatedBlockIds.set(id);
1677 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001678 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001679 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001680 }
1681 }
1682 continue;
1683 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001684 DefinitionMap definitions = b.fBefore;
1685
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001686 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1687 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001688 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001689 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001690 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001691 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001692 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001693 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001694 break;
1695 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001696 this->addDefinitions(*iter, &definitions);
1697 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001698
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001699 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001700 break;
1701 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001702 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001703 madeChanges |= optimizationContext.fUpdated;
1704 } while (optimizationContext.fUpdated);
1705 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001706
Ethan Nicholas91a10532017-06-22 11:24:38 -04001707 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001708 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001709 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1710 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001711 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001712 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001713 switch (s.kind()) {
1714 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001715 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001716 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001717 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001718 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001719 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001720 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001721 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001722 if (s.as<SwitchStatement>().isStatic() &&
1723 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1724 optimizationContext.fSilences.find(&s) ==
1725 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001726 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001727 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001728 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001729 break;
1730 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001731 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001732 break;
1733 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001734 } else {
1735 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001736 }
1737 }
1738 }
1739
ethannicholas22f939e2016-10-13 13:25:34 -07001740 // check for missing return
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001741 if (f.declaration().returnType() != *fContext->fVoid_Type) {
John Stiles61e75e32020-10-01 15:42:37 -04001742 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001743 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001744 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001745 }
1746 }
John Stiles0cc193a2020-09-09 09:39:34 -04001747
1748 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001749}
1750
Brian Osman32d53552020-09-23 13:55:20 -04001751std::unique_ptr<Program> Compiler::convertProgram(
1752 Program::Kind kind,
1753 String text,
1754 const Program::Settings& settings,
1755 const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
1756 SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001757
Brian Osman0006ad02020-11-18 15:38:39 -05001758 // Loading and optimizing our base module might reset the inliner, so do that first,
1759 // *then* configure the inliner with the settings for this program.
1760 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1761
ethannicholasb3058bd2016-07-01 08:22:01 -07001762 fErrorText = "";
1763 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001764 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001765
1766 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001767 std::unique_ptr<String> textPtr(new String(std::move(text)));
1768 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001769
John Stiles5c7bb322020-10-22 11:09:15 -04001770 // Enable node pooling while converting and optimizing the program for a performance boost.
1771 // The Program will take ownership of the pool.
John Stiles2d68ea32020-10-22 15:42:27 -04001772 std::unique_ptr<Pool> pool = Pool::Create();
1773 pool->attachToThread();
Brian Osman0006ad02020-11-18 15:38:39 -05001774 IRGenerator::IRBundle ir =
1775 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
1776 textPtr->c_str(), textPtr->size(), externalValues);
John Stiles5c7bb322020-10-22 11:09:15 -04001777 auto program = std::make_unique<Program>(kind,
1778 std::move(textPtr),
1779 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001780 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001781 fContext,
1782 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001783 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001784 std::move(ir.fModifiers),
1785 std::move(ir.fSymbolTable),
1786 std::move(pool),
1787 ir.fInputs);
1788 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001789 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001790 // Do not return programs that failed to compile.
1791 } else if (settings.fOptimize && !this->optimize(*program)) {
1792 // Do not return programs that failed to optimize.
1793 } else {
1794 // We have a successful program!
1795 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001796 }
John Stiles5c7bb322020-10-22 11:09:15 -04001797
1798 program->fPool->detachFromThread();
1799 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001800}
1801
Brian Osman0006ad02020-11-18 15:38:39 -05001802bool Compiler::optimize(LoadedModule& module) {
1803 SkASSERT(!fErrorCount);
1804 Program::Settings settings;
1805 fIRGenerator->fKind = module.fKind;
1806 fIRGenerator->fSettings = &settings;
1807 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1808
1809 fInliner.reset(fModifiers.back().get(), &settings);
1810
1811 while (fErrorCount == 0) {
1812 bool madeChanges = false;
1813
1814 // Scan and optimize based on the control-flow graph for each function.
1815 for (const auto& element : module.fElements) {
1816 if (element->is<FunctionDefinition>()) {
1817 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1818 }
1819 }
1820
1821 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001822 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001823
1824 if (!madeChanges) {
1825 break;
1826 }
1827 }
1828 return fErrorCount == 0;
1829}
1830
Ethan Nicholas00543112018-07-31 09:44:36 -04001831bool Compiler::optimize(Program& program) {
1832 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001833 fIRGenerator->fKind = program.fKind;
1834 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001835 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001836
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001837 while (fErrorCount == 0) {
1838 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001839
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001840 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001841 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001842 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001843 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001844 }
1845 }
1846
1847 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001848 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001849
1850 // Remove dead functions. We wait until after analysis so that we still report errors,
1851 // even in unused code.
1852 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001853 auto isDeadFunction = [&](const ProgramElement* element) {
1854 if (!element->is<FunctionDefinition>()) {
1855 return false;
1856 }
1857 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1858 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1859 usage->remove(*element);
1860 madeChanges = true;
1861 return true;
1862 }
1863 return false;
1864 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001865 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001866 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001867 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001868 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001869 }),
1870 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001871 program.fSharedElements.erase(
1872 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1873 isDeadFunction),
1874 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001875 }
1876
1877 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001878 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001879 auto isDeadVariable = [&](const ProgramElement* element) {
1880 if (!element->is<GlobalVarDeclaration>()) {
1881 return false;
1882 }
1883 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1884 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1885 if (usage->isDead(varDecl.var())) {
1886 madeChanges = true;
1887 return true;
1888 }
1889 return false;
1890 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001891 program.fElements.erase(
1892 std::remove_if(program.fElements.begin(), program.fElements.end(),
1893 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001894 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001895 }),
1896 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001897 program.fSharedElements.erase(
1898 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1899 isDeadVariable),
1900 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001901 }
John Stiles73a6bff2020-09-09 13:40:37 -04001902
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001903 if (!madeChanges) {
1904 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001905 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001906 }
1907 return fErrorCount == 0;
1908}
1909
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001910#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1911
Ethan Nicholas00543112018-07-31 09:44:36 -04001912bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001913#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001914 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001915 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001916 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001917 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001918 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001919 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001920 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001921 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001922 String errors;
1923 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1924 const char* m) {
1925 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001926 };
1927 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001928
1929 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1930 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1931 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1932 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1933
1934 if (!result) {
1935#if defined(SKSL_STANDALONE)
1936 // Convert the string-stream to a SPIR-V disassembly.
1937 std::string disassembly;
1938 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1939 errors.append(disassembly);
1940 }
1941 this->error(-1, errors);
1942#else
1943 SkDEBUGFAILF("%s", errors.c_str());
1944#endif
1945 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001946 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001947 }
1948#else
Brian Osman88cda172020-10-09 12:05:16 -04001949 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001950 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001951 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001952#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001953 return result;
1954}
1955
Ethan Nicholas00543112018-07-31 09:44:36 -04001956bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001957 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001958 bool result = this->toSPIRV(program, buffer);
1959 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001960 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001961 }
1962 return result;
1963}
1964
Ethan Nicholas00543112018-07-31 09:44:36 -04001965bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001966 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001967 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001968 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001969 return result;
1970}
1971
Ethan Nicholas00543112018-07-31 09:44:36 -04001972bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001973 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001974 bool result = this->toGLSL(program, buffer);
1975 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001976 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001977 }
1978 return result;
1979}
1980
Brian Osmanc0243912020-02-19 15:35:26 -05001981bool Compiler::toHLSL(Program& program, String* out) {
1982 String spirv;
1983 if (!this->toSPIRV(program, &spirv)) {
1984 return false;
1985 }
1986
1987 return SPIRVtoHLSL(spirv, out);
1988}
1989
Ethan Nicholas00543112018-07-31 09:44:36 -04001990bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001991 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001992 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001993 return result;
1994}
1995
Ethan Nicholas00543112018-07-31 09:44:36 -04001996bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001997 StringStream buffer;
1998 bool result = this->toMetal(program, buffer);
1999 if (result) {
2000 *out = buffer.str();
2001 }
2002 return result;
2003}
2004
Greg Daniela28ea672020-09-25 11:12:56 -04002005#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002006bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002007 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002008 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002009 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04002010 return result;
2011}
2012
Ethan Nicholas00543112018-07-31 09:44:36 -04002013bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002014 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002015 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002016 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002017 return result;
2018}
Greg Daniela28ea672020-09-25 11:12:56 -04002019#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002020
Ethan Nicholas2a479a52020-08-18 16:29:45 -04002021#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04002022
2023#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04002024bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04002025 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04002026 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05002027 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04002028 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002029 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05002030 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04002031 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04002032 return result;
2033}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04002034#endif
2035
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002036std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Brian Osman88cda172020-10-09 12:05:16 -04002037 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002038 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04002039 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
2040 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04002041 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002042 return result;
2043 }
2044 return nullptr;
2045}
2046
Brian Osman401a0092020-09-10 14:47:24 -04002047const char* Compiler::OperatorName(Token::Kind op) {
2048 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002049 case Token::Kind::TK_PLUS: return "+";
2050 case Token::Kind::TK_MINUS: return "-";
2051 case Token::Kind::TK_STAR: return "*";
2052 case Token::Kind::TK_SLASH: return "/";
2053 case Token::Kind::TK_PERCENT: return "%";
2054 case Token::Kind::TK_SHL: return "<<";
2055 case Token::Kind::TK_SHR: return ">>";
2056 case Token::Kind::TK_LOGICALNOT: return "!";
2057 case Token::Kind::TK_LOGICALAND: return "&&";
2058 case Token::Kind::TK_LOGICALOR: return "||";
2059 case Token::Kind::TK_LOGICALXOR: return "^^";
2060 case Token::Kind::TK_BITWISENOT: return "~";
2061 case Token::Kind::TK_BITWISEAND: return "&";
2062 case Token::Kind::TK_BITWISEOR: return "|";
2063 case Token::Kind::TK_BITWISEXOR: return "^";
2064 case Token::Kind::TK_EQ: return "=";
2065 case Token::Kind::TK_EQEQ: return "==";
2066 case Token::Kind::TK_NEQ: return "!=";
2067 case Token::Kind::TK_LT: return "<";
2068 case Token::Kind::TK_GT: return ">";
2069 case Token::Kind::TK_LTEQ: return "<=";
2070 case Token::Kind::TK_GTEQ: return ">=";
2071 case Token::Kind::TK_PLUSEQ: return "+=";
2072 case Token::Kind::TK_MINUSEQ: return "-=";
2073 case Token::Kind::TK_STAREQ: return "*=";
2074 case Token::Kind::TK_SLASHEQ: return "/=";
2075 case Token::Kind::TK_PERCENTEQ: return "%=";
2076 case Token::Kind::TK_SHLEQ: return "<<=";
2077 case Token::Kind::TK_SHREQ: return ">>=";
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002078 case Token::Kind::TK_BITWISEANDEQ: return "&=";
2079 case Token::Kind::TK_BITWISEOREQ: return "|=";
2080 case Token::Kind::TK_BITWISEXOREQ: return "^=";
2081 case Token::Kind::TK_PLUSPLUS: return "++";
2082 case Token::Kind::TK_MINUSMINUS: return "--";
2083 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002084 default:
Brian Osman401a0092020-09-10 14:47:24 -04002085 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002086 }
2087}
2088
2089
2090bool Compiler::IsAssignment(Token::Kind op) {
2091 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002092 case Token::Kind::TK_EQ: // fall through
2093 case Token::Kind::TK_PLUSEQ: // fall through
2094 case Token::Kind::TK_MINUSEQ: // fall through
2095 case Token::Kind::TK_STAREQ: // fall through
2096 case Token::Kind::TK_SLASHEQ: // fall through
2097 case Token::Kind::TK_PERCENTEQ: // fall through
2098 case Token::Kind::TK_SHLEQ: // fall through
2099 case Token::Kind::TK_SHREQ: // fall through
2100 case Token::Kind::TK_BITWISEOREQ: // fall through
2101 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05002102 case Token::Kind::TK_BITWISEANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002103 return true;
2104 default:
2105 return false;
2106 }
2107}
2108
Brian Osman401a0092020-09-10 14:47:24 -04002109Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
2110 switch (op) {
2111 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
2112 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
2113 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
2114 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
2115 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
2116 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
2117 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
2118 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
2119 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
2120 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
Brian Osman401a0092020-09-10 14:47:24 -04002121 default: return op;
2122 }
2123}
2124
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002125Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05002126 if (fSource && offset >= 0) {
2127 int line = 1;
2128 int column = 1;
2129 for (int i = 0; i < offset; i++) {
2130 if ((*fSource)[i] == '\n') {
2131 ++line;
2132 column = 1;
2133 }
2134 else {
2135 ++column;
2136 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002137 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05002138 return Position(line, column);
2139 } else {
2140 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002141 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002142}
2143
2144void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002145 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002146 Position pos = this->position(offset);
Ethan Nicholas3c729892020-12-07 12:47:17 -05002147 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07002148}
2149
Ethan Nicholasdcd2f862020-12-17 23:24:25 +00002150String Compiler::errorText() {
2151 this->writeErrorCount();
Ethan Nicholas00543112018-07-31 09:44:36 -04002152 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002153 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07002154 return result;
2155}
2156
2157void Compiler::writeErrorCount() {
2158 if (fErrorCount) {
2159 fErrorText += to_string(fErrorCount) + " error";
2160 if (fErrorCount > 1) {
2161 fErrorText += "s";
2162 }
2163 fErrorText += "\n";
2164 }
2165}
2166
John Stilesa6841be2020-08-06 14:11:56 -04002167} // namespace SkSL