blob: 17a329d855e16f7f241d5dc416731f08e01acc24 [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
John Stiles54e7c052021-01-11 14:22:36 -050098#define TYPE(t) fContext->fTypes.f ## t .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",
John Stiles54e7c052021-01-11 14:22:36 -0500166 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500167 /*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
John Stiles54e7c052021-01-11 14:22:36 -0500228 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400229
John Stiles54e7c052021-01-11 14:22:36 -0500230 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
231 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
232 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400233
John Stiles54e7c052021-01-11 14:22:36 -0500234 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
235 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
236 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400237
John Stiles54e7c052021-01-11 14:22:36 -0500238 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
239 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
240 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400241
John Stiles54e7c052021-01-11 14:22:36 -0500242 fRuntimeEffectModule.fSymbols->addAlias("mat2x2", fContext->fTypes.fFloat2x2.get());
243 fRuntimeEffectModule.fSymbols->addAlias("mat2x3", fContext->fTypes.fFloat2x3.get());
244 fRuntimeEffectModule.fSymbols->addAlias("mat2x4", fContext->fTypes.fFloat2x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400245
John Stiles54e7c052021-01-11 14:22:36 -0500246 fRuntimeEffectModule.fSymbols->addAlias("mat3x2", fContext->fTypes.fFloat3x2.get());
247 fRuntimeEffectModule.fSymbols->addAlias("mat3x3", fContext->fTypes.fFloat3x3.get());
248 fRuntimeEffectModule.fSymbols->addAlias("mat3x4", fContext->fTypes.fFloat3x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400249
John Stiles54e7c052021-01-11 14:22:36 -0500250 fRuntimeEffectModule.fSymbols->addAlias("mat4x2", fContext->fTypes.fFloat4x2.get());
251 fRuntimeEffectModule.fSymbols->addAlias("mat4x3", fContext->fTypes.fFloat4x3.get());
252 fRuntimeEffectModule.fSymbols->addAlias("mat4x4", fContext->fTypes.fFloat4x4.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(),
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500308 /*externalFunctions=*/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;
ethannicholas22f939e2016-10-13 13:25:34 -0700428 default:
429 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400430 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700431 }
432}
433
434// add local variables defined by this node to the set
John Stiles796cdb72020-10-08 12:06:53 -0400435void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) {
John Stiles70025e52020-09-28 16:08:58 -0400436 if (node.isExpression()) {
437 Expression* expr = node.expression()->get();
438 switch (expr->kind()) {
439 case Expression::Kind::kBinary: {
440 BinaryExpression* b = &expr->as<BinaryExpression>();
441 if (b->getOperator() == Token::Kind::TK_EQ) {
John Stiles2d4f9592020-10-30 10:29:12 -0400442 this->addDefinition(b->left().get(), &b->right(), definitions);
John Stiles70025e52020-09-28 16:08:58 -0400443 } else if (Compiler::IsAssignment(b->getOperator())) {
444 this->addDefinition(
John Stiles2d4f9592020-10-30 10:29:12 -0400445 b->left().get(),
John Stiles70025e52020-09-28 16:08:58 -0400446 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
447 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500448
ethannicholas22f939e2016-10-13 13:25:34 -0700449 }
John Stiles70025e52020-09-28 16:08:58 -0400450 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700451 }
John Stiles70025e52020-09-28 16:08:58 -0400452 case Expression::Kind::kFunctionCall: {
453 const FunctionCall& c = expr->as<FunctionCall>();
Brian Osman5bf3e202020-10-13 10:34:18 -0400454 const std::vector<const Variable*>& parameters = c.function().parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400455 for (size_t i = 0; i < parameters.size(); ++i) {
456 if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stiles70025e52020-09-28 16:08:58 -0400457 this->addDefinition(
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400458 c.arguments()[i].get(),
John Stiles70025e52020-09-28 16:08:58 -0400459 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
460 definitions);
461 }
462 }
463 break;
464 }
465 case Expression::Kind::kPrefix: {
466 const PrefixExpression* p = &expr->as<PrefixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400467 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
468 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400469 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400470 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400471 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
472 definitions);
473 }
474 break;
475 }
476 case Expression::Kind::kPostfix: {
477 const PostfixExpression* p = &expr->as<PostfixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400478 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
479 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400480 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400481 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400482 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
483 definitions);
484 }
485 break;
486 }
487 case Expression::Kind::kVariableReference: {
488 const VariableReference* v = &expr->as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400489 if (v->refKind() != VariableReference::RefKind::kRead) {
John Stiles70025e52020-09-28 16:08:58 -0400490 this->addDefinition(
491 v,
492 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
493 definitions);
494 }
495 break;
496 }
497 default:
498 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700499 }
John Stiles70025e52020-09-28 16:08:58 -0400500 } else if (node.isStatement()) {
501 Statement* stmt = node.statement()->get();
502 if (stmt->is<VarDeclaration>()) {
503 VarDeclaration& vd = stmt->as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400504 if (vd.value()) {
505 definitions->set(&vd.var(), &vd.value());
ethannicholas22f939e2016-10-13 13:25:34 -0700506 }
ethannicholas22f939e2016-10-13 13:25:34 -0700507 }
508 }
509}
510
John Stilese6150002020-10-05 12:03:53 -0400511void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700512 BasicBlock& block = cfg->fBlocks[blockId];
513
514 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500515 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700516 for (const BasicBlock::Node& n : block.fNodes) {
517 this->addDefinitions(n, &after);
518 }
519
520 // propagate definitions to exits
521 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400522 if (exitId == blockId) {
523 continue;
524 }
ethannicholas22f939e2016-10-13 13:25:34 -0700525 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500526 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400527 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
528 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400529 // exit has no definition for it, just copy it and reprocess exit block
530 processedSet->reset(exitId);
John Stiles796cdb72020-10-08 12:06:53 -0400531 exit.fBefore[var] = e1;
ethannicholas22f939e2016-10-13 13:25:34 -0700532 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500533 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400534 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700535 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400536 // definition has changed, merge and reprocess the exit block
537 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500538 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400539 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500540 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400541 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500542 }
ethannicholas22f939e2016-10-13 13:25:34 -0700543 }
544 }
John Stiles65b48272020-12-22 17:18:34 -0500545 }
ethannicholas22f939e2016-10-13 13:25:34 -0700546 }
547}
548
549// returns a map which maps all local variables in the function to null, indicating that their value
550// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500551static DefinitionMap compute_start_state(const CFG& cfg) {
552 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400553 for (const auto& block : cfg.fBlocks) {
554 for (const auto& node : block.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -0400555 if (node.isStatement()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400556 const Statement* s = node.statement()->get();
Brian Osmanc0213602020-10-06 14:43:32 -0400557 if (s->is<VarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400558 result[&s->as<VarDeclaration>().var()] = nullptr;
ethannicholas22f939e2016-10-13 13:25:34 -0700559 }
560 }
561 }
562 }
563 return result;
564}
565
Ethan Nicholascb670962017-04-20 19:31:52 -0400566/**
567 * Returns true if assigning to this lvalue has no effect.
568 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400569static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400570 switch (lvalue.kind()) {
571 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400572 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400573 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400574 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400575 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400576 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400577 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400578 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400579 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400580 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400581 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400582 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400583 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400584 return !t.test()->hasSideEffects() &&
585 is_dead(*t.ifTrue(), usage) &&
586 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500587 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400588 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500589#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400590 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500591#endif
592 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400593 }
594}
ethannicholas22f939e2016-10-13 13:25:34 -0700595
Ethan Nicholascb670962017-04-20 19:31:52 -0400596/**
597 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
598 * to a dead target and lack of side effects on the left hand side.
599 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400600static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400601 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400602 return false;
603 }
John Stiles2d4f9592020-10-30 10:29:12 -0400604 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400605}
606
607void Compiler::computeDataFlow(CFG* cfg) {
608 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400609
610 // We set bits in the "processed" set after a block has been scanned.
611 SkBitSet processedSet(cfg->fBlocks.size());
612 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
613 processedSet.set(*blockId);
614 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700615 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400616}
617
618/**
619 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
620 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
621 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
622 * need to be regenerated).
623 */
John Stilesafbf8992020-08-18 10:08:21 -0400624static bool try_replace_expression(BasicBlock* b,
625 std::vector<BasicBlock::Node>::iterator* iter,
626 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400627 std::unique_ptr<Expression>* target = (*iter)->expression();
628 if (!b->tryRemoveExpression(iter)) {
629 *target = std::move(*newExpression);
630 return false;
631 }
632 *target = std::move(*newExpression);
633 return b->tryInsertExpression(iter, target);
634}
635
636/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400637 * Returns true if the expression is a constant numeric literal with the specified value, or a
638 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400639 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400640template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400641static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400642 switch (expr.kind()) {
643 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400644 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400645
Ethan Nicholase6592142020-09-08 10:22:09 -0400646 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400647 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400648
Ethan Nicholase6592142020-09-08 10:22:09 -0400649 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400650 const Constructor& constructor = expr.as<Constructor>();
651 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400652 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400653 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400654 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500655 if (constructor.componentType().isFloat()) {
656 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400657 if (constructor.getFVecComponent(i) != value) {
658 return false;
659 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500660 }
661 return true;
662 } else if (constructor.componentType().isInteger()) {
663 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400664 if (constructor.getIVecComponent(i) != value) {
665 return false;
666 }
667 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500668 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400669 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500670 // Other types (e.g. boolean) might occur, but aren't supported here.
671 return false;
John Stiles9d944232020-08-19 09:56:49 -0400672
Ethan Nicholase6592142020-09-08 10:22:09 -0400673 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400674 SkASSERT(constructor.arguments().size() == 1);
675 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400676
677 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400678 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400679 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400680 }
681 return false;
682 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400683 default:
684 return false;
685 }
686}
687
688/**
689 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
690 * and CFG structures).
691 */
John Stilesafbf8992020-08-18 10:08:21 -0400692static void delete_left(BasicBlock* b,
693 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400694 Compiler::OptimizationContext* optimizationContext) {
695 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400696 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400697 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400698 Expression& left = *bin.left();
699 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400700 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400701 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400702 if (bin.getOperator() == Token::Kind::TK_EQ) {
703 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400704 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400705 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400706 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400707 // Remove references within LHS.
708 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400709 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400710 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400711 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400712 return;
713 }
714 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400715 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400716 return;
717 }
718 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400719 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400720 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400721 return;
722 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400723 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400724 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400725}
726
727/**
728 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
729 * CFG structures).
730 */
John Stilesafbf8992020-08-18 10:08:21 -0400731static void delete_right(BasicBlock* b,
732 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400733 Compiler::OptimizationContext* optimizationContext) {
734 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400735 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400736 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400737 std::unique_ptr<Expression>& leftPointer = bin.left();
738 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400739 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400740 // Remove references within RHS.
741 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400742 if (!b->tryRemoveExpressionBefore(iter, &right)) {
743 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400744 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400745 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400746 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400747 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400748 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400749 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400750 return;
751 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400752 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400753 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400754 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400755 return;
756 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400757 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400758 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400759}
760
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400761/**
762 * Constructs the specified type using a single argument.
763 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400764static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400765 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400766 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400767 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400768 return result;
769}
770
771/**
772 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
773 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
774 */
775static void vectorize(BasicBlock* b,
776 std::vector<BasicBlock::Node>::iterator* iter,
777 const Type& type,
778 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400779 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400780 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500781 SkASSERT(type.isVector());
782 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400783 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400784 std::unique_ptr<Expression>* target = (*iter)->expression();
785 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400786 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400787 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400788 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400789 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400790 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400791 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400792 }
793 }
794}
795
796/**
797 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
798 * left to yield vec<n>(x).
799 */
800static void vectorize_left(BasicBlock* b,
801 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400802 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400803 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400804 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400805 optimizationContext->fUsage->remove(bin.right().get());
806 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400807}
808
809/**
810 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
811 * right to yield vec<n>(y).
812 */
813static void vectorize_right(BasicBlock* b,
814 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400815 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400816 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400817 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400818 optimizationContext->fUsage->remove(bin.left().get());
819 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400820}
821
822// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400823static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400824 switch (expr.kind()) {
825 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400826 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400827 break;
828 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400829 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400830 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400831 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400832 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400833 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400834 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400835 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400836 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400837 break;
838 default:
839 ABORT("shouldn't be writing to this kind of expression\n");
840 break;
841 }
842}
843
Ethan Nicholascb670962017-04-20 19:31:52 -0400844void Compiler::simplifyExpression(DefinitionMap& definitions,
845 BasicBlock& b,
846 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400847 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400848 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400849 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500850
Ethan Nicholascb670962017-04-20 19:31:52 -0400851 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400852 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
853 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400854 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400855 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400856 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400857 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400858 // Remove references within 'expr', add references within 'optimized'
859 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400860 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400861 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400862 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400863 }
John Stiles70025e52020-09-28 16:08:58 -0400864 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400865 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400866 }
867 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400868 switch (expr->kind()) {
869 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400870 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400871 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400872 if (ref.refKind() != VariableReference::RefKind::kWrite &&
873 ref.refKind() != VariableReference::RefKind::kPointer &&
874 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400875 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
876 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000877 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400878 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400879 }
880 break;
881 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400882 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400883 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400884 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400885 // ternary has a constant test, replace it with either the true or
886 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400887 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400888 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400889 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400890 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400891 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400892 optimizationContext->fUpdated = true;
893 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400894 }
895 break;
896 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400897 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400898 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400899 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400900 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400901 break;
902 }
John Stiles2d4f9592020-10-30 10:29:12 -0400903 Expression& left = *bin->left();
904 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400905 const Type& leftType = left.type();
906 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400907 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500908 if ((!leftType.isScalar() && !leftType.isVector()) ||
909 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400910 break;
911 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400912 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400913 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400914 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500915 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400916 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400917 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400918 } else {
919 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400920 // 1 * float4(x) -> float4(x)
921 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400922 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400923 }
924 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400925 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500926 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400927 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400928 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400929 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400930 } else {
931 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400932 // float4(0) * x -> float4(0)
933 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400934 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400935 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500936 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400937 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400938 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400939 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500940 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400941 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400942 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400943 } else {
944 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400945 // float4(x) * 1 -> float4(x)
946 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400947 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400948 }
949 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400950 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500951 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400952 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400953 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400954 } else {
955 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400956 // x * float4(0) -> float4(0)
957 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400958 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400959 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500960 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400961 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400962 }
963 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400964 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400965 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500966 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400967 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400968 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400969 } else {
970 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400971 // 0 + float4(x) -> float4(x)
972 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400973 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400974 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400975 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500976 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400977 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400978 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400979 } else {
980 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400981 // float4(x) + 0 -> float4(x)
982 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400983 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400984 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400985 }
986 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400987 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400988 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500989 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400990 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400991 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400992 } else {
993 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400994 // float4(x) - 0 -> float4(x)
995 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400996 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400997 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400998 }
999 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001000 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001001 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -05001002 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001003 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001004 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001005 } else {
1006 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001007 // float4(x) / 1 -> float4(x)
1008 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001009 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001010 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001011 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -05001012 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001013 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001014 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001015 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001016 } else {
1017 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001018 // float4(0) / x -> float4(0)
1019 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001020 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001021 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001022 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001023 }
1024 }
1025 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001026 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001027 if (is_constant(right, 0)) {
1028 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001029 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001030 }
1031 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001032 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001033 if (is_constant(right, 0)) {
1034 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001035 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001036 }
1037 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001038 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001039 if (is_constant(right, 1)) {
1040 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001041 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001042 }
1043 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001044 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001045 if (is_constant(right, 1)) {
1046 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001047 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001048 }
1049 break;
1050 default:
1051 break;
1052 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001053 break;
1054 }
John Stilesf5c1d042020-11-21 23:26:07 -05001055 case Expression::Kind::kConstructor: {
1056 // Find constructors embedded inside constructors and flatten them out where possible.
1057 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
1058 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
1059 // Leave single-argument constructors alone, though. These might be casts or splats.
1060 Constructor& c = expr->as<Constructor>();
1061 if (c.type().columns() > 1) {
1062 // Inspect each constructor argument to see if it's a candidate for flattening.
1063 // Remember matched arguments in a bitfield, "argsToOptimize".
1064 int argsToOptimize = 0;
1065 int currBit = 1;
1066 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1067 if (arg->is<Constructor>()) {
1068 Constructor& inner = arg->as<Constructor>();
1069 if (inner.arguments().size() > 1 &&
1070 inner.type().componentType() == c.type().componentType()) {
1071 argsToOptimize |= currBit;
1072 }
1073 }
1074 currBit <<= 1;
1075 }
1076 if (argsToOptimize) {
1077 // We found at least one argument that could be flattened out. Re-walk the
1078 // constructor args and flatten the candidates we found during our initial pass.
1079 ExpressionArray flattened;
1080 flattened.reserve_back(c.type().columns());
1081 currBit = 1;
1082 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1083 if (argsToOptimize & currBit) {
1084 Constructor& inner = arg->as<Constructor>();
1085 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
1086 flattened.push_back(innerArg->clone());
1087 }
1088 } else {
1089 flattened.push_back(arg->clone());
1090 }
1091 currBit <<= 1;
1092 }
1093 auto optimized = std::unique_ptr<Expression>(
1094 new Constructor(c.fOffset, &c.type(), std::move(flattened)));
1095 // No fUsage change; no references have been added or removed anywhere.
1096 optimizationContext->fUpdated = true;
1097 if (!try_replace_expression(&b, iter, &optimized)) {
1098 optimizationContext->fNeedsRescan = true;
1099 return;
1100 }
1101 SkASSERT((*iter)->isExpression());
1102 break;
1103 }
1104 }
1105 break;
1106 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001107 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001108 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -05001109 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001110 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001111 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001112 for (int i = 0; i < (int) s.components().size(); ++i) {
1113 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001114 identity = false;
1115 break;
1116 }
1117 }
1118 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001119 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001120 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001121 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001122 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001123 return;
1124 }
John Stiles70025e52020-09-28 16:08:58 -04001125 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001126 break;
1127 }
1128 }
John Stiles108bbe22020-11-18 11:10:38 -05001129 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1130 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001131 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001132 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001133 for (int c : s.components()) {
1134 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001135 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001136 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001137 final));
John Stilesd2f51b12021-01-07 18:12:31 -05001138 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -05001139 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -05001140 try_replace_expression(&b, iter, &replacement);
1141 optimizationContext->fUpdated = true;
1142 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001143 break;
1144 }
1145 // Optimize swizzles of constructors.
1146 if (s.base()->is<Constructor>()) {
1147 Constructor& base = s.base()->as<Constructor>();
1148 std::unique_ptr<Expression> replacement;
1149 const Type& componentType = base.type().componentType();
1150 int swizzleSize = s.components().size();
1151
1152 // The IR generator has already converted any zero/one swizzle components into
1153 // constructors containing zero/one args. Confirm that this is true by checking that
1154 // our swizzle components are all `xyzw` (values 0 through 3).
1155 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1156 [](int8_t c) { return c >= 0 && c <= 3; }));
1157
John Stiles9aeed132020-11-24 17:36:06 -05001158 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001159 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1160 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001161 const Expression& argument = *base.arguments().front();
1162 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1163 /*rows=*/1);
1164 replacement = Constructor::SimplifyConversion(constructorType, argument);
1165 if (!replacement) {
1166 ExpressionArray newArgs;
1167 newArgs.push_back(argument.clone());
1168 replacement = std::make_unique<Constructor>(base.fOffset, &constructorType,
1169 std::move(newArgs));
1170 }
John Stiles108bbe22020-11-18 11:10:38 -05001171
John Stilesa60ac0c2020-12-22 08:59:51 -05001172 // We're replacing an expression with a cloned version; we'll need a rescan.
1173 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1174 // reference counts.
1175 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001176 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001177 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001178 break;
1179 }
1180
John Stiles0777ac42020-11-19 11:06:47 -05001181 // Swizzles can duplicate some elements and discard others, e.g.
1182 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1183 // - Expressions with side effects need to occur exactly once, even if they
1184 // would otherwise be swizzle-eliminated
1185 // - Non-trivial expressions should not be repeated, but elimination is OK.
1186 //
1187 // Look up the argument for the constructor at each index. This is typically simple
1188 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1189 // seems. This example would result in:
1190 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1191 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1192 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1193 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1194 struct ConstructorArgMap {
1195 int8_t fArgIndex;
1196 int8_t fComponent;
1197 };
1198
1199 int numConstructorArgs = base.type().columns();
1200 ConstructorArgMap argMap[4] = {};
1201 int writeIdx = 0;
1202 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1203 const Expression& expr = *base.arguments()[argIdx];
1204 int argWidth = expr.type().columns();
1205 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1206 argMap[writeIdx].fArgIndex = argIdx;
1207 argMap[writeIdx].fComponent = componentIdx;
1208 ++writeIdx;
1209 }
1210 }
1211 SkASSERT(writeIdx == numConstructorArgs);
1212
1213 // Count up the number of times each constructor argument is used by the
1214 // swizzle.
1215 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1216 // - bar.yz is referenced 3 times, by `.x_xy`
1217 // - half(foo) is referenced 1 time, by `._w__`
1218 int8_t exprUsed[4] = {};
1219 for (int c : s.components()) {
1220 exprUsed[argMap[c].fArgIndex]++;
1221 }
1222
1223 bool safeToOptimize = true;
1224 for (int index = 0; index < numConstructorArgs; ++index) {
1225 int8_t constructorArgIndex = argMap[index].fArgIndex;
1226 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1227
1228 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001229 if (exprUsed[constructorArgIndex] > 1 &&
1230 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001231 safeToOptimize = false;
1232 break;
1233 }
1234 // Check that side-effect-bearing expressions are swizzled in exactly once.
1235 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1236 safeToOptimize = false;
1237 break;
1238 }
1239 }
1240
1241 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001242 struct ReorderedArgument {
1243 int8_t fArgIndex;
1244 ComponentArray fComponents;
1245 };
1246 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001247 for (int c : s.components()) {
1248 const ConstructorArgMap& argument = argMap[c];
1249 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1250
John Stiles9aeed132020-11-24 17:36:06 -05001251 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001252 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001253 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001254 reorderedArgs.push_back({argument.fArgIndex,
1255 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001256 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001257 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001258 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001259 if (reorderedArgs.empty() ||
1260 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1261 // This can't be combined with the previous argument. Add a new one.
1262 reorderedArgs.push_back({argument.fArgIndex,
1263 ComponentArray{argument.fComponent}});
1264 } else {
1265 // Since we know this argument uses components, it should already
1266 // have at least one component set.
1267 SkASSERT(!reorderedArgs.back().fComponents.empty());
1268 // Build up the current argument with one more component.
1269 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1270 }
John Stiles0777ac42020-11-19 11:06:47 -05001271 }
1272 }
John Stilesd9076cb2020-11-19 12:18:36 -05001273
1274 // Convert our reordered argument list to an actual array of expressions, with
1275 // the new order and any new inner swizzles that need to be applied. Note that
1276 // we expect followup passes to clean up the inner swizzles.
1277 ExpressionArray newArgs;
1278 newArgs.reserve_back(swizzleSize);
1279 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1280 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1281 if (reorderedArg.fComponents.empty()) {
1282 newArgs.push_back(baseArg.clone());
1283 } else {
1284 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1285 reorderedArg.fComponents));
1286 }
1287 }
1288
1289 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001290 replacement = std::make_unique<Constructor>(
1291 base.fOffset,
1292 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1293 std::move(newArgs));
1294
John Stilesa60ac0c2020-12-22 08:59:51 -05001295 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001296 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001297
1298 // We're replacing an expression with a cloned version; we'll need a rescan.
1299 try_replace_expression(&b, iter, &replacement);
1300 optimizationContext->fUpdated = true;
1301 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001302 }
John Stiles108bbe22020-11-18 11:10:38 -05001303 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001304 }
John Stiles30212b72020-06-11 17:55:07 -04001305 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001306 }
1307 default:
1308 break;
1309 }
1310}
1311
John Stiles92219b42020-06-15 12:32:24 -04001312// Returns true if this statement could potentially execute a break at the current level. We ignore
1313// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001314static bool contains_conditional_break(Statement& stmt) {
1315 class ContainsConditionalBreak : public ProgramVisitor {
1316 public:
1317 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001318 switch (stmt.kind()) {
1319 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001320 return this->INHERITED::visitStatement(stmt);
1321
Ethan Nicholase6592142020-09-08 10:22:09 -04001322 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001323 return fInConditional > 0;
1324
Ethan Nicholase6592142020-09-08 10:22:09 -04001325 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001326 ++fInConditional;
1327 bool result = this->INHERITED::visitStatement(stmt);
1328 --fInConditional;
1329 return result;
1330 }
1331
1332 default:
1333 return false;
1334 }
1335 }
1336
1337 int fInConditional = 0;
1338 using INHERITED = ProgramVisitor;
1339 };
1340
1341 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001342}
1343
Ethan Nicholas5005a222018-08-24 13:06:27 -04001344// returns true if this statement definitely executes a break at the current level (we ignore
1345// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001346static bool contains_unconditional_break(Statement& stmt) {
1347 class ContainsUnconditionalBreak : public ProgramVisitor {
1348 public:
1349 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001350 switch (stmt.kind()) {
1351 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001352 return this->INHERITED::visitStatement(stmt);
1353
Ethan Nicholase6592142020-09-08 10:22:09 -04001354 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001355 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001356
1357 default:
1358 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001359 }
John Stilesb92641c2020-08-31 18:09:01 -04001360 }
John Stiles92219b42020-06-15 12:32:24 -04001361
John Stilesb92641c2020-08-31 18:09:01 -04001362 using INHERITED = ProgramVisitor;
1363 };
John Stiles92219b42020-06-15 12:32:24 -04001364
John Stilesb92641c2020-08-31 18:09:01 -04001365 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001366}
1367
John Stiles8f2a0cf2020-10-13 12:48:21 -04001368static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001369 switch (stmt->kind()) {
1370 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001371 // Recurse into the block.
1372 Block& block = static_cast<Block&>(*stmt);
1373
John Stiles8f2a0cf2020-10-13 12:48:21 -04001374 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001375 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001376 for (std::unique_ptr<Statement>& stmt : block.children()) {
1377 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001378 }
John Stiles92219b42020-06-15 12:32:24 -04001379
1380 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001381 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001382 break;
John Stiles92219b42020-06-15 12:32:24 -04001383 }
1384
Ethan Nicholase6592142020-09-08 10:22:09 -04001385 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001386 // Do not append a break to the target.
1387 break;
1388
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001389 default:
John Stiles92219b42020-06-15 12:32:24 -04001390 // Append normal statements to the target.
1391 target->push_back(std::move(stmt));
1392 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001393 }
1394}
1395
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001396// Returns a block containing all of the statements that will be run if the given case matches
1397// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1398// broken by this call and must then be discarded).
1399// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1400// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001401static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1402 SwitchCase* caseToCapture) {
1403 // We have to be careful to not move any of the pointers until after we're sure we're going to
1404 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1405 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001406 auto iter = switchStatement->cases().begin();
1407 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001408 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001409 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001410 }
John Stiles92219b42020-06-15 12:32:24 -04001411 }
1412
1413 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1414 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1415 // statements that we can use for simplification.
1416 auto startIter = iter;
1417 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001418 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001419 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001420 if (contains_conditional_break(*stmt)) {
1421 // We can't reduce switch-cases to a block when they have conditional breaks.
1422 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001423 }
John Stiles92219b42020-06-15 12:32:24 -04001424
1425 if (contains_unconditional_break(*stmt)) {
1426 // We found an unconditional break. We can use this block, but we need to strip
1427 // out the break statement.
1428 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001429 break;
1430 }
1431 }
John Stiles92219b42020-06-15 12:32:24 -04001432
1433 if (unconditionalBreakStmt != nullptr) {
1434 break;
1435 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001436 }
John Stiles92219b42020-06-15 12:32:24 -04001437
1438 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1439 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001440 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001441
1442 // We can move over most of the statements as-is.
1443 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001444 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001445 caseStmts.push_back(std::move(stmt));
1446 }
1447 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001448 }
John Stiles92219b42020-06-15 12:32:24 -04001449
1450 // If we found an unconditional break at the end, we need to move what we can while avoiding
1451 // that break.
1452 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001453 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001454 if (stmt.get() == unconditionalBreakStmt) {
1455 move_all_but_break(stmt, &caseStmts);
1456 unconditionalBreakStmt = nullptr;
1457 break;
1458 }
1459
1460 caseStmts.push_back(std::move(stmt));
1461 }
1462 }
1463
1464 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1465
1466 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001467 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001468}
1469
Ethan Nicholascb670962017-04-20 19:31:52 -04001470void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001471 BasicBlock& b,
1472 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001473 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001474 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001475 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001476 switch (stmt->kind()) {
1477 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001478 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001479 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001480 (!varDecl.value() ||
1481 !varDecl.value()->hasSideEffects())) {
1482 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001483 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001484 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001485 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001486 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001487 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001488 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001489 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001490 }
1491 break;
1492 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001493 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001494 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001495 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001496 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001497 if (i.test()->as<BoolLiteral>().value()) {
1498 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001499 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001500 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001501 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001502 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001503 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001504 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001505 }
1506 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001507 optimizationContext->fUpdated = true;
1508 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001509 break;
1510 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001511 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001512 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001513 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001514 optimizationContext->fUpdated = true;
1515 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001516 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001517 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001518 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001519 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001520 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001521 (*iter)->setStatement(
1522 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001523 } else {
1524 // no if, no else, no test side effects, kill the whole if
1525 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001526 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001527 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001528 optimizationContext->fUpdated = true;
1529 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001530 }
1531 break;
1532 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001533 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001534 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001535 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001536 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001537 // switch is constant, replace it with the case that matches
1538 bool found = false;
1539 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001540 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1541 if (!c->value()) {
1542 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001543 continue;
1544 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001545 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001546 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001547 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001548 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001549 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001550 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001551 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001552 break;
1553 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001554 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1555 optimizationContext->fSilences.find(&s) ==
1556 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001557 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001558 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001559 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001560 }
1561 return; // can't simplify
1562 }
1563 }
1564 }
1565 if (!found) {
1566 // no matching case. use default if it exists, or kill the whole thing
1567 if (defaultCase) {
1568 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1569 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001570 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001571 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001572 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1573 optimizationContext->fSilences.find(&s) ==
1574 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001575 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001576 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001577 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001578 }
1579 return; // can't simplify
1580 }
1581 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001582 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001583 }
1584 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001585 optimizationContext->fUpdated = true;
1586 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001587 }
1588 break;
1589 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001590 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001591 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001592 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001593 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001594 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001595 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001596 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001597 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001598 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001599 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001600 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001601 }
1602 break;
1603 }
1604 default:
1605 break;
1606 }
1607}
1608
Brian Osman010ce6a2020-10-19 16:34:10 -04001609bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001610 bool madeChanges = false;
1611
Ethan Nicholascb670962017-04-20 19:31:52 -04001612 CFG cfg = CFGGenerator().getCFG(f);
1613 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001614
1615 // check for unreachable code
1616 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001617 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001618 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001619 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001620 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001621 if (node.isStatement()) {
1622 offset = (*node.statement())->fOffset;
1623 } else {
1624 offset = (*node.expression())->fOffset;
1625 if ((*node.expression())->is<BoolLiteral>()) {
1626 // Function inlining can generate do { ... } while(false) loops which always
1627 // break, so the boolean condition is considered unreachable. Since not being
1628 // able to reach a literal is a non-issue in the first place, we don't report an
1629 // error in this case.
1630 continue;
1631 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001632 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001633 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001634 }
1635 }
1636 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001637 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001638 }
1639
Ethan Nicholascb670962017-04-20 19:31:52 -04001640 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001641 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001642 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001643 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001644 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001645 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001646 cfg = CFGGenerator().getCFG(f);
1647 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001648 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001649 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001650
John Stiles7d3f0892020-11-03 11:35:01 -05001651 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001652 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001653
1654 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1655 if (eliminatedBlockIds.test(blockId)) {
1656 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1657 optimizationContext.fUpdated = true;
1658 optimizationContext.fNeedsRescan = true;
1659 break;
1660 }
1661
1662 BasicBlock& b = cfg.fBlocks[blockId];
1663 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001664 // Block was reachable before optimization, but has since become unreachable. In
1665 // addition to being dead code, it's broken - since control flow can't reach it, no
1666 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001667 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001668 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001669 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001670 // Eliminating a node runs the risk of eliminating that node's exits as
1671 // well. Keep track of this and do a rescan if we are about to access one
1672 // of these.
1673 for (BlockId id : b.fExits) {
1674 eliminatedBlockIds.set(id);
1675 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001676 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001677 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001678 }
1679 }
1680 continue;
1681 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001682 DefinitionMap definitions = b.fBefore;
1683
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001684 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1685 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001686 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001687 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001688 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001689 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001690 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001691 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001692 break;
1693 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001694 this->addDefinitions(*iter, &definitions);
1695 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001696
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001697 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001698 break;
1699 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001700 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001701 madeChanges |= optimizationContext.fUpdated;
1702 } while (optimizationContext.fUpdated);
1703 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001704
Ethan Nicholas91a10532017-06-22 11:24:38 -04001705 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001706 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001707 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1708 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001709 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001710 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001711 switch (s.kind()) {
1712 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001713 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001714 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001715 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001716 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001717 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001718 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001719 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001720 if (s.as<SwitchStatement>().isStatic() &&
1721 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1722 optimizationContext.fSilences.find(&s) ==
1723 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001724 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001725 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001726 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001727 break;
1728 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001729 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001730 break;
1731 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001732 } else {
1733 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001734 }
1735 }
1736 }
1737
ethannicholas22f939e2016-10-13 13:25:34 -07001738 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001739 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001740 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001741 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001742 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001743 }
1744 }
John Stiles0cc193a2020-09-09 09:39:34 -04001745
1746 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001747}
1748
Brian Osman32d53552020-09-23 13:55:20 -04001749std::unique_ptr<Program> Compiler::convertProgram(
1750 Program::Kind kind,
1751 String text,
1752 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001753 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
1754 SkASSERT(!externalFunctions || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001755
Brian Osman0006ad02020-11-18 15:38:39 -05001756 // Loading and optimizing our base module might reset the inliner, so do that first,
1757 // *then* configure the inliner with the settings for this program.
1758 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1759
ethannicholasb3058bd2016-07-01 08:22:01 -07001760 fErrorText = "";
1761 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001762 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001763
1764 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001765 std::unique_ptr<String> textPtr(new String(std::move(text)));
1766 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001767
John Stiles5c7bb322020-10-22 11:09:15 -04001768 // Enable node pooling while converting and optimizing the program for a performance boost.
1769 // The Program will take ownership of the pool.
John Stiles2d68ea32020-10-22 15:42:27 -04001770 std::unique_ptr<Pool> pool = Pool::Create();
1771 pool->attachToThread();
Brian Osman0006ad02020-11-18 15:38:39 -05001772 IRGenerator::IRBundle ir =
1773 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001774 textPtr->c_str(), textPtr->size(), externalFunctions);
John Stiles5c7bb322020-10-22 11:09:15 -04001775 auto program = std::make_unique<Program>(kind,
1776 std::move(textPtr),
1777 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001778 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001779 fContext,
1780 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001781 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001782 std::move(ir.fModifiers),
1783 std::move(ir.fSymbolTable),
1784 std::move(pool),
1785 ir.fInputs);
1786 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001787 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001788 // Do not return programs that failed to compile.
1789 } else if (settings.fOptimize && !this->optimize(*program)) {
1790 // Do not return programs that failed to optimize.
1791 } else {
1792 // We have a successful program!
1793 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001794 }
John Stiles5c7bb322020-10-22 11:09:15 -04001795
1796 program->fPool->detachFromThread();
1797 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001798}
1799
Brian Osman0006ad02020-11-18 15:38:39 -05001800bool Compiler::optimize(LoadedModule& module) {
1801 SkASSERT(!fErrorCount);
1802 Program::Settings settings;
1803 fIRGenerator->fKind = module.fKind;
1804 fIRGenerator->fSettings = &settings;
1805 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1806
1807 fInliner.reset(fModifiers.back().get(), &settings);
1808
1809 while (fErrorCount == 0) {
1810 bool madeChanges = false;
1811
1812 // Scan and optimize based on the control-flow graph for each function.
1813 for (const auto& element : module.fElements) {
1814 if (element->is<FunctionDefinition>()) {
1815 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1816 }
1817 }
1818
1819 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001820 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001821
1822 if (!madeChanges) {
1823 break;
1824 }
1825 }
1826 return fErrorCount == 0;
1827}
1828
Ethan Nicholas00543112018-07-31 09:44:36 -04001829bool Compiler::optimize(Program& program) {
1830 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001831 fIRGenerator->fKind = program.fKind;
1832 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001833 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001834
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001835 while (fErrorCount == 0) {
1836 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001837
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001838 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001839 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001840 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001841 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001842 }
1843 }
1844
1845 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001846 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001847
1848 // Remove dead functions. We wait until after analysis so that we still report errors,
1849 // even in unused code.
1850 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001851 auto isDeadFunction = [&](const ProgramElement* element) {
1852 if (!element->is<FunctionDefinition>()) {
1853 return false;
1854 }
1855 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1856 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1857 usage->remove(*element);
1858 madeChanges = true;
1859 return true;
1860 }
1861 return false;
1862 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001863 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001864 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001865 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001866 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001867 }),
1868 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001869 program.fSharedElements.erase(
1870 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1871 isDeadFunction),
1872 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001873 }
1874
1875 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001876 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001877 auto isDeadVariable = [&](const ProgramElement* element) {
1878 if (!element->is<GlobalVarDeclaration>()) {
1879 return false;
1880 }
1881 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1882 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1883 if (usage->isDead(varDecl.var())) {
1884 madeChanges = true;
1885 return true;
1886 }
1887 return false;
1888 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001889 program.fElements.erase(
1890 std::remove_if(program.fElements.begin(), program.fElements.end(),
1891 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001892 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001893 }),
1894 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001895 program.fSharedElements.erase(
1896 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1897 isDeadVariable),
1898 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001899 }
John Stiles73a6bff2020-09-09 13:40:37 -04001900
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001901 if (!madeChanges) {
1902 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001903 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001904 }
1905 return fErrorCount == 0;
1906}
1907
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001908#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1909
Ethan Nicholas00543112018-07-31 09:44:36 -04001910bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001911#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001912 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001913 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001914 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001915 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001916 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001917 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001918 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001919 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001920 String errors;
1921 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1922 const char* m) {
1923 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001924 };
1925 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001926
1927 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1928 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1929 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1930 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1931
1932 if (!result) {
1933#if defined(SKSL_STANDALONE)
1934 // Convert the string-stream to a SPIR-V disassembly.
1935 std::string disassembly;
1936 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1937 errors.append(disassembly);
1938 }
1939 this->error(-1, errors);
1940#else
1941 SkDEBUGFAILF("%s", errors.c_str());
1942#endif
1943 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001944 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001945 }
1946#else
Brian Osman88cda172020-10-09 12:05:16 -04001947 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001948 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001949 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001950#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001951 return result;
1952}
1953
Ethan Nicholas00543112018-07-31 09:44:36 -04001954bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001955 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001956 bool result = this->toSPIRV(program, buffer);
1957 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001958 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001959 }
1960 return result;
1961}
1962
Ethan Nicholas00543112018-07-31 09:44:36 -04001963bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001964 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001965 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001966 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001967 return result;
1968}
1969
Ethan Nicholas00543112018-07-31 09:44:36 -04001970bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001971 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001972 bool result = this->toGLSL(program, buffer);
1973 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001974 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001975 }
1976 return result;
1977}
1978
Brian Osmanc0243912020-02-19 15:35:26 -05001979bool Compiler::toHLSL(Program& program, String* out) {
1980 String spirv;
1981 if (!this->toSPIRV(program, &spirv)) {
1982 return false;
1983 }
1984
1985 return SPIRVtoHLSL(spirv, out);
1986}
1987
Ethan Nicholas00543112018-07-31 09:44:36 -04001988bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001989 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001990 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001991 return result;
1992}
1993
Ethan Nicholas00543112018-07-31 09:44:36 -04001994bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001995 StringStream buffer;
1996 bool result = this->toMetal(program, buffer);
1997 if (result) {
1998 *out = buffer.str();
1999 }
2000 return result;
2001}
2002
Greg Daniela28ea672020-09-25 11:12:56 -04002003#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002004bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002005 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002006 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002007 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04002008 return result;
2009}
2010
Ethan Nicholas00543112018-07-31 09:44:36 -04002011bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002012 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002013 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002014 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002015 return result;
2016}
Greg Daniela28ea672020-09-25 11:12:56 -04002017#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002018
Ethan Nicholas2a479a52020-08-18 16:29:45 -04002019#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04002020
2021#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04002022bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04002023 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04002024 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05002025 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04002026 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002027 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05002028 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04002029 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04002030 return result;
2031}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04002032#endif
2033
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002034std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Brian Osman88cda172020-10-09 12:05:16 -04002035 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002036 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04002037 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
2038 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04002039 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002040 return result;
2041 }
2042 return nullptr;
2043}
2044
Brian Osman401a0092020-09-10 14:47:24 -04002045const char* Compiler::OperatorName(Token::Kind op) {
2046 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002047 case Token::Kind::TK_PLUS: return "+";
2048 case Token::Kind::TK_MINUS: return "-";
2049 case Token::Kind::TK_STAR: return "*";
2050 case Token::Kind::TK_SLASH: return "/";
2051 case Token::Kind::TK_PERCENT: return "%";
2052 case Token::Kind::TK_SHL: return "<<";
2053 case Token::Kind::TK_SHR: return ">>";
2054 case Token::Kind::TK_LOGICALNOT: return "!";
2055 case Token::Kind::TK_LOGICALAND: return "&&";
2056 case Token::Kind::TK_LOGICALOR: return "||";
2057 case Token::Kind::TK_LOGICALXOR: return "^^";
2058 case Token::Kind::TK_BITWISENOT: return "~";
2059 case Token::Kind::TK_BITWISEAND: return "&";
2060 case Token::Kind::TK_BITWISEOR: return "|";
2061 case Token::Kind::TK_BITWISEXOR: return "^";
2062 case Token::Kind::TK_EQ: return "=";
2063 case Token::Kind::TK_EQEQ: return "==";
2064 case Token::Kind::TK_NEQ: return "!=";
2065 case Token::Kind::TK_LT: return "<";
2066 case Token::Kind::TK_GT: return ">";
2067 case Token::Kind::TK_LTEQ: return "<=";
2068 case Token::Kind::TK_GTEQ: return ">=";
2069 case Token::Kind::TK_PLUSEQ: return "+=";
2070 case Token::Kind::TK_MINUSEQ: return "-=";
2071 case Token::Kind::TK_STAREQ: return "*=";
2072 case Token::Kind::TK_SLASHEQ: return "/=";
2073 case Token::Kind::TK_PERCENTEQ: return "%=";
2074 case Token::Kind::TK_SHLEQ: return "<<=";
2075 case Token::Kind::TK_SHREQ: return ">>=";
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002076 case Token::Kind::TK_BITWISEANDEQ: return "&=";
2077 case Token::Kind::TK_BITWISEOREQ: return "|=";
2078 case Token::Kind::TK_BITWISEXOREQ: return "^=";
2079 case Token::Kind::TK_PLUSPLUS: return "++";
2080 case Token::Kind::TK_MINUSMINUS: return "--";
2081 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002082 default:
Brian Osman401a0092020-09-10 14:47:24 -04002083 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002084 }
2085}
2086
2087
2088bool Compiler::IsAssignment(Token::Kind op) {
2089 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002090 case Token::Kind::TK_EQ: // fall through
2091 case Token::Kind::TK_PLUSEQ: // fall through
2092 case Token::Kind::TK_MINUSEQ: // fall through
2093 case Token::Kind::TK_STAREQ: // fall through
2094 case Token::Kind::TK_SLASHEQ: // fall through
2095 case Token::Kind::TK_PERCENTEQ: // fall through
2096 case Token::Kind::TK_SHLEQ: // fall through
2097 case Token::Kind::TK_SHREQ: // fall through
2098 case Token::Kind::TK_BITWISEOREQ: // fall through
2099 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05002100 case Token::Kind::TK_BITWISEANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002101 return true;
2102 default:
2103 return false;
2104 }
2105}
2106
Brian Osman401a0092020-09-10 14:47:24 -04002107Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
2108 switch (op) {
2109 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
2110 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
2111 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
2112 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
2113 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
2114 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
2115 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
2116 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
2117 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
2118 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
Brian Osman401a0092020-09-10 14:47:24 -04002119 default: return op;
2120 }
2121}
2122
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002123Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05002124 if (fSource && offset >= 0) {
2125 int line = 1;
2126 int column = 1;
2127 for (int i = 0; i < offset; i++) {
2128 if ((*fSource)[i] == '\n') {
2129 ++line;
2130 column = 1;
2131 }
2132 else {
2133 ++column;
2134 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002135 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05002136 return Position(line, column);
2137 } else {
2138 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002139 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002140}
2141
2142void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002143 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002144 Position pos = this->position(offset);
Ethan Nicholas3c729892020-12-07 12:47:17 -05002145 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07002146}
2147
Ethan Nicholas95046142021-01-07 10:57:27 -05002148String Compiler::errorText(bool showCount) {
2149 if (showCount) {
2150 this->writeErrorCount();
2151 }
Ethan Nicholas00543112018-07-31 09:44:36 -04002152 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002153 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05002154 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07002155 return result;
2156}
2157
2158void Compiler::writeErrorCount() {
2159 if (fErrorCount) {
2160 fErrorText += to_string(fErrorCount) + " error";
2161 if (fErrorCount > 1) {
2162 fErrorText += "s";
2163 }
2164 fErrorText += "\n";
2165 }
2166}
2167
John Stilesa6841be2020-08-06 14:11:56 -04002168} // namespace SkSL