blob: ae6c225525e95e812c27b29e6d74f3cc0309f4d7 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stilesb92641c2020-08-31 18:09:01 -040013#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/sksl/SkSLByteCodeGenerator.h"
15#include "src/sksl/SkSLCFGGenerator.h"
16#include "src/sksl/SkSLCPPCodeGenerator.h"
17#include "src/sksl/SkSLGLSLCodeGenerator.h"
18#include "src/sksl/SkSLHCodeGenerator.h"
19#include "src/sksl/SkSLIRGenerator.h"
20#include "src/sksl/SkSLMetalCodeGenerator.h"
21#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040022#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050024#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/ir/SkSLEnum.h"
26#include "src/sksl/ir/SkSLExpression.h"
27#include "src/sksl/ir/SkSLExpressionStatement.h"
28#include "src/sksl/ir/SkSLFunctionCall.h"
29#include "src/sksl/ir/SkSLIntLiteral.h"
30#include "src/sksl/ir/SkSLModifiersDeclaration.h"
31#include "src/sksl/ir/SkSLNop.h"
32#include "src/sksl/ir/SkSLSymbolTable.h"
33#include "src/sksl/ir/SkSLTernaryExpression.h"
34#include "src/sksl/ir/SkSLUnresolvedFunction.h"
35#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040036#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070037
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040038#include <fstream>
39
Ethan Nicholasa11035b2019-11-26 16:27:47 -050040#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
41#include "include/gpu/GrContextOptions.h"
42#include "src/gpu/GrShaderCaps.h"
43#endif
44
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040045#ifdef SK_ENABLE_SPIRV_VALIDATION
46#include "spirv-tools/libspirv.hpp"
47#endif
48
Brian Osman3d87e9f2020-10-08 11:50:22 -040049#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040050
Brian Osman3d87e9f2020-10-08 11:50:22 -040051// In standalone mode, we load the textual sksl source files. GN generates or copies these files
52// to the skslc executable directory. The "data" in this mode is just the filename.
53#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
54
55#else
56
57// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040058#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
59#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
60#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
61#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
62#include "src/sksl/generated/sksl_interp.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050063#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050064#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040065#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
66
Brian Osman3d87e9f2020-10-08 11:50:22 -040067#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
68 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040069
70#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040071
ethannicholasb3058bd2016-07-01 08:22:01 -070072namespace SkSL {
73
Brian Osman88cda172020-10-09 12:05:16 -040074class AutoSource {
75public:
76 AutoSource(Compiler* compiler, const String* source)
77 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
78 fCompiler->fSource = source;
79 }
80
81 ~AutoSource() { fCompiler->fSource = fOldSource; }
82
83 Compiler* fCompiler;
84 const String* fOldSource;
85};
86
Brian Osmand7e76592020-11-02 12:26:22 -050087Compiler::Compiler(const ShaderCapsClass* caps, Flags flags)
Brian Osman0006ad02020-11-18 15:38:39 -050088 : fContext(std::make_shared<Context>())
89 , fCaps(caps)
John Stiles7b920442020-12-17 10:43:41 -050090 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -050091 , fFlags(flags)
92 , fErrorCount(0) {
93 SkASSERT(fCaps);
John Stiles7c3515b2020-10-16 18:38:39 -040094 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050095 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stiles0f464502020-11-20 12:52:22 -050096 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), fCaps, *this);
ethannicholasb3058bd2016-07-01 08:22:01 -070097
Brian Osmanb06301e2020-11-06 11:45:36 -050098#define TYPE(t) fContext->f##t##_Type.get()
ethannicholasb3058bd2016-07-01 08:22:01 -070099
Brian Osmanb06301e2020-11-06 11:45:36 -0500100 const SkSL::Symbol* rootTypes[] = {
101 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500102
Brian Osmanb06301e2020-11-06 11:45:36 -0500103 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
104 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
105 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
106 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
107 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
108 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
109 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
110 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
111 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500112
Brian Osmanb06301e2020-11-06 11:45:36 -0500113 TYPE(Float2x2), TYPE(Float2x3), TYPE(Float2x4),
114 TYPE(Float3x2), TYPE(Float3x3), TYPE(Float3x4),
115 TYPE(Float4x2), TYPE(Float4x3), TYPE(Float4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500116
Brian Osmanb06301e2020-11-06 11:45:36 -0500117 TYPE(Half2x2), TYPE(Half2x3), TYPE(Half2x4),
118 TYPE(Half3x2), TYPE(Half3x3), TYPE(Half3x4),
119 TYPE(Half4x2), TYPE(Half4x3), TYPE(Half4x4),
ethannicholasb3058bd2016-07-01 08:22:01 -0700120
Brian Osmanb06301e2020-11-06 11:45:36 -0500121 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenUType), TYPE(GenBType),
John Stilesd06d4a92020-12-10 12:54:31 -0500122 TYPE(Mat), TYPE(MatH), TYPE(Vec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500123 TYPE(GVec), TYPE(GVec2), TYPE(GVec3), TYPE(GVec4),
124 TYPE(HVec), TYPE(IVec), TYPE(UVec), TYPE(SVec), TYPE(USVec),
125 TYPE(ByteVec), TYPE(UByteVec), TYPE(BVec),
126
127 TYPE(FragmentProcessor),
128 };
129
130 const SkSL::Symbol* privateTypes[] = {
131 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
132 TYPE(SamplerExternalOES),
133 TYPE(SamplerCube),
134 TYPE(Sampler2DRect),
135 TYPE(Sampler1DArray), TYPE(Sampler2DArray), TYPE(SamplerCubeArray),
136 TYPE(SamplerBuffer),
137 TYPE(Sampler2DMS), TYPE(Sampler2DMSArray),
138
139 TYPE(ISampler2D),
140 TYPE(Image2D), TYPE(IImage2D),
141 TYPE(SubpassInput), TYPE(SubpassInputMS),
142
143 TYPE(GSampler1D), TYPE(GSampler2D), TYPE(GSampler3D),
144 TYPE(GSamplerCube),
145 TYPE(GSampler2DRect),
146 TYPE(GSampler1DArray), TYPE(GSampler2DArray), TYPE(GSamplerCubeArray),
147 TYPE(GSamplerBuffer),
148 TYPE(GSampler2DMS), TYPE(GSampler2DMSArray),
149
150 TYPE(Sampler1DShadow), TYPE(Sampler2DShadow), TYPE(SamplerCubeShadow),
151 TYPE(Sampler2DRectShadow),
152 TYPE(Sampler1DArrayShadow), TYPE(Sampler2DArrayShadow), TYPE(SamplerCubeArrayShadow),
153
154 TYPE(GSampler2DArrayShadow), TYPE(GSamplerCubeArrayShadow),
155 TYPE(Sampler),
156 TYPE(Texture2D),
157 };
158
159 for (const SkSL::Symbol* type : rootTypes) {
160 fRootSymbolTable->addWithoutOwnership(type);
161 }
162 for (const SkSL::Symbol* type : privateTypes) {
163 fPrivateSymbolTable->addWithoutOwnership(type);
164 }
165
166#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700167
Brian Osman3887a012020-09-30 13:22:27 -0400168 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
169 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500170 fPrivateSymbolTable->add(
171 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500172 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500173 "sk_Caps",
174 fContext->fSkCaps_Type.get(),
175 /*builtin=*/false,
176 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500177
Brian Osman3d87e9f2020-10-08 11:50:22 -0400178 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500179 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700180}
181
John Stilesdd13dba2020-10-29 10:45:34 -0400182Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700183
Brian Osman56269982020-11-20 12:38:07 -0500184const ParsedModule& Compiler::loadGPUModule() {
185 if (!fGPUModule.fSymbols) {
186 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
187 }
188 return fGPUModule;
189}
190
191const ParsedModule& Compiler::loadFragmentModule() {
192 if (!fFragmentModule.fSymbols) {
193 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag),
194 this->loadGPUModule());
195 }
196 return fFragmentModule;
197}
198
199const ParsedModule& Compiler::loadVertexModule() {
200 if (!fVertexModule.fSymbols) {
201 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert),
202 this->loadGPUModule());
203 }
204 return fVertexModule;
205}
206
Brian Osman88cda172020-10-09 12:05:16 -0400207const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400208 if (!fGeometryModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500209 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom),
210 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400211 }
Brian Osman88cda172020-10-09 12:05:16 -0400212 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400213}
214
Brian Osman88cda172020-10-09 12:05:16 -0400215const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400216 if (!fFPModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500217 fFPModule = this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp),
218 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400219 }
Brian Osman88cda172020-10-09 12:05:16 -0400220 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400221}
222
Brian Osmanb06301e2020-11-06 11:45:36 -0500223const ParsedModule& Compiler::loadPublicModule() {
224 if (!fPublicModule.fSymbols) {
225 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
226 }
227 return fPublicModule;
228}
229
Brian Osman91946752020-12-21 13:20:40 -0500230const ParsedModule& Compiler::loadRuntimeEffectModule() {
231 if (!fRuntimeEffectModule.fSymbols) {
232 fRuntimeEffectModule = this->parseModule(Program::kRuntimeEffect_Kind, MODULE_DATA(runtime),
233 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400234
Brian Osman91946752020-12-21 13:20:40 -0500235 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
236 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fFragmentProcessor_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400237
Brian Osman91946752020-12-21 13:20:40 -0500238 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fFloat2_Type.get());
239 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fFloat3_Type.get());
240 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fFloat4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400241
Brian Osman91946752020-12-21 13:20:40 -0500242 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fBool2_Type.get());
243 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fBool3_Type.get());
244 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fBool4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400245
Brian Osman91946752020-12-21 13:20:40 -0500246 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fFloat2x2_Type.get());
247 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fFloat3x3_Type.get());
248 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fFloat4x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400249
Brian Osman91946752020-12-21 13:20:40 -0500250 fRuntimeEffectModule.fSymbols->addAlias("mat2x2", fContext->fFloat2x2_Type.get());
251 fRuntimeEffectModule.fSymbols->addAlias("mat2x3", fContext->fFloat2x3_Type.get());
252 fRuntimeEffectModule.fSymbols->addAlias("mat2x4", fContext->fFloat2x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400253
Brian Osman91946752020-12-21 13:20:40 -0500254 fRuntimeEffectModule.fSymbols->addAlias("mat3x2", fContext->fFloat3x2_Type.get());
255 fRuntimeEffectModule.fSymbols->addAlias("mat3x3", fContext->fFloat3x3_Type.get());
256 fRuntimeEffectModule.fSymbols->addAlias("mat3x4", fContext->fFloat3x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400257
Brian Osman91946752020-12-21 13:20:40 -0500258 fRuntimeEffectModule.fSymbols->addAlias("mat4x2", fContext->fFloat4x2_Type.get());
259 fRuntimeEffectModule.fSymbols->addAlias("mat4x3", fContext->fFloat4x3_Type.get());
260 fRuntimeEffectModule.fSymbols->addAlias("mat4x4", fContext->fFloat4x4_Type.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400261 }
Brian Osman91946752020-12-21 13:20:40 -0500262 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400263}
264
Brian Osman88cda172020-10-09 12:05:16 -0400265const ParsedModule& Compiler::loadInterpreterModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400266 if (!fInterpreterModule.fSymbols) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500267 fInterpreterModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(interp),
268 this->loadPublicModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400269 }
Brian Osman88cda172020-10-09 12:05:16 -0400270 return fInterpreterModule;
271}
272
273const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
274 switch (kind) {
Brian Osman91946752020-12-21 13:20:40 -0500275 case Program::kVertex_Kind: return this->loadVertexModule(); break;
276 case Program::kFragment_Kind: return this->loadFragmentModule(); break;
277 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
278 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
279 case Program::kRuntimeEffect_Kind: return this->loadRuntimeEffectModule(); break;
280 case Program::kGeneric_Kind: return this->loadInterpreterModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400281 }
282 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400283}
284
Brian Osman3d87e9f2020-10-08 11:50:22 -0400285LoadedModule Compiler::loadModule(Program::Kind kind,
286 ModuleData data,
287 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400288 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500289 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
290 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
291 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
292 // like samplers or textures. Today, 'Private' does contain the union of all known types,
293 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
294 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
295 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400296 }
297
298#if defined(SKSL_STANDALONE)
299 SkASSERT(data.fPath);
300 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400301 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
302 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400303 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400304 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400305 abort();
306 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400307 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400308 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400309 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400310 SkASSERT(fIRGenerator->fCanInline);
311 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400312 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500313 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500314 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500315 /*isBuiltinCode=*/true, source->c_str(), source->length(),
316 /*externalValues=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400317 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500318 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400319 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400320 if (this->fErrorCount) {
321 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400322 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400323 }
Brian Osman88cda172020-10-09 12:05:16 -0400324 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400325#else
326 SkASSERT(data.fData && (data.fSize != 0));
327 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
328 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500329 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400330 fModifiers.push_back(fIRGenerator->releaseModifiers());
331#endif
332
333 return module;
334}
335
336ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500337 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
338 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400339
340 // For modules that just declare (but don't define) intrinsic functions, there will be no new
341 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500342 if (module.fElements.empty()) {
343 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400344 }
345
346 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
347
348 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
349 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500350 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400351 switch (element->kind()) {
352 case ProgramElement::Kind::kFunction: {
353 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400354 SkASSERT(f.declaration().isBuiltin());
355 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400356 break;
357 }
John Stiles569249b2020-11-03 12:18:22 -0500358 case ProgramElement::Kind::kFunctionPrototype: {
359 // These are already in the symbol table.
360 break;
361 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400362 case ProgramElement::Kind::kEnum: {
363 const Enum& e = element->as<Enum>();
364 SkASSERT(e.isBuiltin());
365 intrinsics->insertOrDie(e.typeName(), std::move(element));
366 break;
367 }
368 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400369 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
370 const Variable& var = global.declaration()->as<VarDeclaration>().var();
371 SkASSERT(var.isBuiltin());
372 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400373 break;
374 }
375 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400376 const Variable& var = element->as<InterfaceBlock>().variable();
377 SkASSERT(var.isBuiltin());
378 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400379 break;
380 }
381 default:
382 printf("Unsupported element: %s\n", element->description().c_str());
383 SkASSERT(false);
384 break;
385 }
386 }
387
Brian Osman0006ad02020-11-18 15:38:39 -0500388 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400389}
390
ethannicholas22f939e2016-10-13 13:25:34 -0700391// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500392void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
393 DefinitionMap* definitions) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400394 switch (lvalue->kind()) {
395 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -0400396 const Variable& var = *lvalue->as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400397 if (var.storage() == Variable::Storage::kLocal) {
John Stiles796cdb72020-10-08 12:06:53 -0400398 definitions->set(&var, expr);
ethannicholas22f939e2016-10-13 13:25:34 -0700399 }
400 break;
401 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400402 case Expression::Kind::kSwizzle:
ethannicholas22f939e2016-10-13 13:25:34 -0700403 // We consider the variable written to as long as at least some of its components have
404 // been written to. This will lead to some false negatives (we won't catch it if you
405 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400406 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
407 // 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 -0700408 // more complicated whole-program analysis. This is probably good enough.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400409 this->addDefinition(lvalue->as<Swizzle>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400410 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700411 definitions);
412 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400413 case Expression::Kind::kIndex:
ethannicholas22f939e2016-10-13 13:25:34 -0700414 // see comments in Swizzle
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400415 this->addDefinition(lvalue->as<IndexExpression>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400416 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700417 definitions);
418 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400419 case Expression::Kind::kFieldAccess:
ethannicholas22f939e2016-10-13 13:25:34 -0700420 // see comments in Swizzle
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400421 this->addDefinition(lvalue->as<FieldAccess>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400422 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700423 definitions);
424 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400425 case Expression::Kind::kTernary:
Ethan Nicholasa583b812018-01-18 13:32:11 -0500426 // To simplify analysis, we just pretend that we write to both sides of the ternary.
427 // This allows for false positives (meaning we fail to detect that a variable might not
428 // have been assigned), but is preferable to false negatives.
Ethan Nicholasdd218162020-10-08 05:48:01 -0400429 this->addDefinition(lvalue->as<TernaryExpression>().ifTrue().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400430 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500431 definitions);
Ethan Nicholasdd218162020-10-08 05:48:01 -0400432 this->addDefinition(lvalue->as<TernaryExpression>().ifFalse().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400433 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500434 definitions);
435 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400436 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400437 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700438 default:
439 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400440 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700441 }
442}
443
444// add local variables defined by this node to the set
John Stiles796cdb72020-10-08 12:06:53 -0400445void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) {
John Stiles70025e52020-09-28 16:08:58 -0400446 if (node.isExpression()) {
447 Expression* expr = node.expression()->get();
448 switch (expr->kind()) {
449 case Expression::Kind::kBinary: {
450 BinaryExpression* b = &expr->as<BinaryExpression>();
451 if (b->getOperator() == Token::Kind::TK_EQ) {
John Stiles2d4f9592020-10-30 10:29:12 -0400452 this->addDefinition(b->left().get(), &b->right(), definitions);
John Stiles70025e52020-09-28 16:08:58 -0400453 } else if (Compiler::IsAssignment(b->getOperator())) {
454 this->addDefinition(
John Stiles2d4f9592020-10-30 10:29:12 -0400455 b->left().get(),
John Stiles70025e52020-09-28 16:08:58 -0400456 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
457 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500458
ethannicholas22f939e2016-10-13 13:25:34 -0700459 }
John Stiles70025e52020-09-28 16:08:58 -0400460 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700461 }
John Stiles70025e52020-09-28 16:08:58 -0400462 case Expression::Kind::kFunctionCall: {
463 const FunctionCall& c = expr->as<FunctionCall>();
Brian Osman5bf3e202020-10-13 10:34:18 -0400464 const std::vector<const Variable*>& parameters = c.function().parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400465 for (size_t i = 0; i < parameters.size(); ++i) {
466 if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stiles70025e52020-09-28 16:08:58 -0400467 this->addDefinition(
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400468 c.arguments()[i].get(),
John Stiles70025e52020-09-28 16:08:58 -0400469 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
470 definitions);
471 }
472 }
473 break;
474 }
475 case Expression::Kind::kPrefix: {
476 const PrefixExpression* p = &expr->as<PrefixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400477 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
478 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400479 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400480 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400481 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
482 definitions);
483 }
484 break;
485 }
486 case Expression::Kind::kPostfix: {
487 const PostfixExpression* p = &expr->as<PostfixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400488 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
489 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400490 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400491 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400492 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
493 definitions);
494 }
495 break;
496 }
497 case Expression::Kind::kVariableReference: {
498 const VariableReference* v = &expr->as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400499 if (v->refKind() != VariableReference::RefKind::kRead) {
John Stiles70025e52020-09-28 16:08:58 -0400500 this->addDefinition(
501 v,
502 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
503 definitions);
504 }
505 break;
506 }
507 default:
508 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700509 }
John Stiles70025e52020-09-28 16:08:58 -0400510 } else if (node.isStatement()) {
511 Statement* stmt = node.statement()->get();
512 if (stmt->is<VarDeclaration>()) {
513 VarDeclaration& vd = stmt->as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400514 if (vd.value()) {
515 definitions->set(&vd.var(), &vd.value());
ethannicholas22f939e2016-10-13 13:25:34 -0700516 }
ethannicholas22f939e2016-10-13 13:25:34 -0700517 }
518 }
519}
520
John Stilese6150002020-10-05 12:03:53 -0400521void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700522 BasicBlock& block = cfg->fBlocks[blockId];
523
524 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500525 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700526 for (const BasicBlock::Node& n : block.fNodes) {
527 this->addDefinitions(n, &after);
528 }
529
530 // propagate definitions to exits
531 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400532 if (exitId == blockId) {
533 continue;
534 }
ethannicholas22f939e2016-10-13 13:25:34 -0700535 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles796cdb72020-10-08 12:06:53 -0400536 after.foreach([&](const Variable* var, std::unique_ptr<Expression>** e1Ptr) {
537 std::unique_ptr<Expression>* e1 = *e1Ptr;
538 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
539 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400540 // exit has no definition for it, just copy it and reprocess exit block
541 processedSet->reset(exitId);
John Stiles796cdb72020-10-08 12:06:53 -0400542 exit.fBefore[var] = e1;
ethannicholas22f939e2016-10-13 13:25:34 -0700543 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500544 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400545 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700546 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400547 // definition has changed, merge and reprocess the exit block
548 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500549 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400550 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500551 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400552 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500553 }
ethannicholas22f939e2016-10-13 13:25:34 -0700554 }
555 }
John Stiles796cdb72020-10-08 12:06:53 -0400556 });
ethannicholas22f939e2016-10-13 13:25:34 -0700557 }
558}
559
560// returns a map which maps all local variables in the function to null, indicating that their value
561// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500562static DefinitionMap compute_start_state(const CFG& cfg) {
563 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400564 for (const auto& block : cfg.fBlocks) {
565 for (const auto& node : block.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -0400566 if (node.isStatement()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400567 const Statement* s = node.statement()->get();
Brian Osmanc0213602020-10-06 14:43:32 -0400568 if (s->is<VarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400569 result[&s->as<VarDeclaration>().var()] = nullptr;
ethannicholas22f939e2016-10-13 13:25:34 -0700570 }
571 }
572 }
573 }
574 return result;
575}
576
Ethan Nicholascb670962017-04-20 19:31:52 -0400577/**
578 * Returns true if assigning to this lvalue has no effect.
579 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400580static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400581 switch (lvalue.kind()) {
582 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400583 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400584 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400585 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400586 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400587 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400588 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400589 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400590 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400591 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400592 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400593 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400594 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400595 return !t.test()->hasSideEffects() &&
596 is_dead(*t.ifTrue(), usage) &&
597 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500598 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400599 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400600 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400601 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500602#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400603 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500604#endif
605 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400606 }
607}
ethannicholas22f939e2016-10-13 13:25:34 -0700608
Ethan Nicholascb670962017-04-20 19:31:52 -0400609/**
610 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
611 * to a dead target and lack of side effects on the left hand side.
612 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400613static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400614 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400615 return false;
616 }
John Stiles2d4f9592020-10-30 10:29:12 -0400617 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400618}
619
620void Compiler::computeDataFlow(CFG* cfg) {
621 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400622
623 // We set bits in the "processed" set after a block has been scanned.
624 SkBitSet processedSet(cfg->fBlocks.size());
625 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
626 processedSet.set(*blockId);
627 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700628 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400629}
630
631/**
632 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
633 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
634 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
635 * need to be regenerated).
636 */
John Stilesafbf8992020-08-18 10:08:21 -0400637static bool try_replace_expression(BasicBlock* b,
638 std::vector<BasicBlock::Node>::iterator* iter,
639 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400640 std::unique_ptr<Expression>* target = (*iter)->expression();
641 if (!b->tryRemoveExpression(iter)) {
642 *target = std::move(*newExpression);
643 return false;
644 }
645 *target = std::move(*newExpression);
646 return b->tryInsertExpression(iter, target);
647}
648
649/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400650 * Returns true if the expression is a constant numeric literal with the specified value, or a
651 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400652 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400653template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400654static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400655 switch (expr.kind()) {
656 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400657 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400658
Ethan Nicholase6592142020-09-08 10:22:09 -0400659 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400660 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400661
Ethan Nicholase6592142020-09-08 10:22:09 -0400662 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400663 const Constructor& constructor = expr.as<Constructor>();
664 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400665 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400666 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400667 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500668 if (constructor.componentType().isFloat()) {
669 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400670 if (constructor.getFVecComponent(i) != value) {
671 return false;
672 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500673 }
674 return true;
675 } else if (constructor.componentType().isInteger()) {
676 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400677 if (constructor.getIVecComponent(i) != value) {
678 return false;
679 }
680 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500681 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400682 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500683 // Other types (e.g. boolean) might occur, but aren't supported here.
684 return false;
John Stiles9d944232020-08-19 09:56:49 -0400685
Ethan Nicholase6592142020-09-08 10:22:09 -0400686 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400687 SkASSERT(constructor.arguments().size() == 1);
688 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400689
690 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400691 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400692 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400693 }
694 return false;
695 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400696 default:
697 return false;
698 }
699}
700
701/**
702 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
703 * and CFG structures).
704 */
John Stilesafbf8992020-08-18 10:08:21 -0400705static void delete_left(BasicBlock* b,
706 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400707 Compiler::OptimizationContext* optimizationContext) {
708 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400709 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400710 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400711 Expression& left = *bin.left();
712 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400713 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400714 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400715 if (bin.getOperator() == Token::Kind::TK_EQ) {
716 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400717 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400718 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400719 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400720 // Remove references within LHS.
721 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400722 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400723 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400724 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400725 return;
726 }
727 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400728 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400729 return;
730 }
731 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400732 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400733 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400734 return;
735 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400736 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400737 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400738}
739
740/**
741 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
742 * CFG structures).
743 */
John Stilesafbf8992020-08-18 10:08:21 -0400744static void delete_right(BasicBlock* b,
745 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400746 Compiler::OptimizationContext* optimizationContext) {
747 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400748 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400749 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400750 std::unique_ptr<Expression>& leftPointer = bin.left();
751 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400752 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400753 // Remove references within RHS.
754 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400755 if (!b->tryRemoveExpressionBefore(iter, &right)) {
756 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400757 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400758 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400759 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400760 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400761 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400762 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400763 return;
764 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400765 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400766 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400767 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400768 return;
769 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400770 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400771 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400772}
773
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400774/**
775 * Constructs the specified type using a single argument.
776 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400777static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400778 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400779 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400780 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400781 return result;
782}
783
784/**
785 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
786 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
787 */
788static void vectorize(BasicBlock* b,
789 std::vector<BasicBlock::Node>::iterator* iter,
790 const Type& type,
791 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400792 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400793 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500794 SkASSERT(type.isVector());
795 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400796 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400797 std::unique_ptr<Expression>* target = (*iter)->expression();
798 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400799 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400800 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400801 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400802 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400803 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400804 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400805 }
806 }
807}
808
809/**
810 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
811 * left to yield vec<n>(x).
812 */
813static void vectorize_left(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 RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400818 optimizationContext->fUsage->remove(bin.right().get());
819 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400820}
821
822/**
823 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
824 * right to yield vec<n>(y).
825 */
826static void vectorize_right(BasicBlock* b,
827 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400828 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400829 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400830 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400831 optimizationContext->fUsage->remove(bin.left().get());
832 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400833}
834
835// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400836static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400837 switch (expr.kind()) {
838 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400839 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400840 break;
841 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400842 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400843 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400844 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400845 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400846 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400847 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400848 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400849 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400850 break;
851 default:
852 ABORT("shouldn't be writing to this kind of expression\n");
853 break;
854 }
855}
856
Ethan Nicholascb670962017-04-20 19:31:52 -0400857void Compiler::simplifyExpression(DefinitionMap& definitions,
858 BasicBlock& b,
859 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400860 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400861 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400862 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500863
Ethan Nicholascb670962017-04-20 19:31:52 -0400864 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400865 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
866 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400867 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400868 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400869 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400870 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400871 // Remove references within 'expr', add references within 'optimized'
872 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400873 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400874 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400875 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400876 }
John Stiles70025e52020-09-28 16:08:58 -0400877 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400878 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400879 }
880 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400881 switch (expr->kind()) {
882 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400883 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400884 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400885 if (ref.refKind() != VariableReference::RefKind::kWrite &&
886 ref.refKind() != VariableReference::RefKind::kPointer &&
887 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400888 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
889 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000890 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400891 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400892 }
893 break;
894 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400895 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400896 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400897 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400898 // ternary has a constant test, replace it with either the true or
899 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400900 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400901 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400902 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400903 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400904 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400905 optimizationContext->fUpdated = true;
906 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400907 }
908 break;
909 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400910 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400911 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400912 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400913 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400914 break;
915 }
John Stiles2d4f9592020-10-30 10:29:12 -0400916 Expression& left = *bin->left();
917 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400918 const Type& leftType = left.type();
919 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400920 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500921 if ((!leftType.isScalar() && !leftType.isVector()) ||
922 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400923 break;
924 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400925 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400926 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400927 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500928 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400929 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400930 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400931 } else {
932 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400933 // 1 * float4(x) -> float4(x)
934 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400935 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400936 }
937 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400938 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500939 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400940 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400941 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400942 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400943 } else {
944 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400945 // float4(0) * x -> float4(0)
946 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400947 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400948 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500949 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400950 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400951 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400952 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500953 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400954 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400955 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400956 } else {
957 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400958 // float4(x) * 1 -> float4(x)
959 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400960 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400961 }
962 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400963 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500964 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400965 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400966 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400967 } else {
968 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400969 // x * float4(0) -> float4(0)
970 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400971 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400972 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500973 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400974 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400975 }
976 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400977 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400978 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500979 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400980 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400981 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400982 } else {
983 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400984 // 0 + float4(x) -> float4(x)
985 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400986 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400987 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400988 } else 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 Nicholas56e42712017-04-21 10:23:37 -0400998 }
999 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001000 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001001 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -05001002 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001003 // x - float4(0) -> 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 - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001007 // float4(x) - 0 -> float4(x)
1008 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001009 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001010 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001011 }
1012 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001013 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001014 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -05001015 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001016 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001017 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001018 } else {
1019 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001020 // float4(x) / 1 -> float4(x)
1021 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001022 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001023 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001024 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -05001025 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001026 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001027 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001028 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001029 } else {
1030 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001031 // float4(0) / x -> float4(0)
1032 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001033 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001034 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001035 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001036 }
1037 }
1038 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001039 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001040 if (is_constant(right, 0)) {
1041 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001042 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001043 }
1044 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001045 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001046 if (is_constant(right, 0)) {
1047 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001048 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001049 }
1050 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001051 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001052 if (is_constant(right, 1)) {
1053 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001054 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001055 }
1056 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001057 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001058 if (is_constant(right, 1)) {
1059 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001060 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001061 }
1062 break;
1063 default:
1064 break;
1065 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001066 break;
1067 }
John Stilesf5c1d042020-11-21 23:26:07 -05001068 case Expression::Kind::kConstructor: {
1069 // Find constructors embedded inside constructors and flatten them out where possible.
1070 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
1071 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
1072 // Leave single-argument constructors alone, though. These might be casts or splats.
1073 Constructor& c = expr->as<Constructor>();
1074 if (c.type().columns() > 1) {
1075 // Inspect each constructor argument to see if it's a candidate for flattening.
1076 // Remember matched arguments in a bitfield, "argsToOptimize".
1077 int argsToOptimize = 0;
1078 int currBit = 1;
1079 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1080 if (arg->is<Constructor>()) {
1081 Constructor& inner = arg->as<Constructor>();
1082 if (inner.arguments().size() > 1 &&
1083 inner.type().componentType() == c.type().componentType()) {
1084 argsToOptimize |= currBit;
1085 }
1086 }
1087 currBit <<= 1;
1088 }
1089 if (argsToOptimize) {
1090 // We found at least one argument that could be flattened out. Re-walk the
1091 // constructor args and flatten the candidates we found during our initial pass.
1092 ExpressionArray flattened;
1093 flattened.reserve_back(c.type().columns());
1094 currBit = 1;
1095 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1096 if (argsToOptimize & currBit) {
1097 Constructor& inner = arg->as<Constructor>();
1098 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
1099 flattened.push_back(innerArg->clone());
1100 }
1101 } else {
1102 flattened.push_back(arg->clone());
1103 }
1104 currBit <<= 1;
1105 }
1106 auto optimized = std::unique_ptr<Expression>(
1107 new Constructor(c.fOffset, &c.type(), std::move(flattened)));
1108 // No fUsage change; no references have been added or removed anywhere.
1109 optimizationContext->fUpdated = true;
1110 if (!try_replace_expression(&b, iter, &optimized)) {
1111 optimizationContext->fNeedsRescan = true;
1112 return;
1113 }
1114 SkASSERT((*iter)->isExpression());
1115 break;
1116 }
1117 }
1118 break;
1119 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001120 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001121 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -05001122 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001123 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001124 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001125 for (int i = 0; i < (int) s.components().size(); ++i) {
1126 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001127 identity = false;
1128 break;
1129 }
1130 }
1131 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001132 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001133 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001134 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001135 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001136 return;
1137 }
John Stiles70025e52020-09-28 16:08:58 -04001138 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001139 break;
1140 }
1141 }
John Stiles108bbe22020-11-18 11:10:38 -05001142 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1143 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001144 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001145 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001146 for (int c : s.components()) {
1147 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001148 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001149 optimizationContext->fUpdated = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001150 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001151 final));
John Stiles108bbe22020-11-18 11:10:38 -05001152 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001153 if (!try_replace_expression(&b, iter, &replacement)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001154 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001155 return;
1156 }
John Stiles70025e52020-09-28 16:08:58 -04001157 SkASSERT((*iter)->isExpression());
John Stiles108bbe22020-11-18 11:10:38 -05001158 break;
1159 }
1160 // Optimize swizzles of constructors.
1161 if (s.base()->is<Constructor>()) {
1162 Constructor& base = s.base()->as<Constructor>();
1163 std::unique_ptr<Expression> replacement;
1164 const Type& componentType = base.type().componentType();
1165 int swizzleSize = s.components().size();
1166
1167 // The IR generator has already converted any zero/one swizzle components into
1168 // constructors containing zero/one args. Confirm that this is true by checking that
1169 // our swizzle components are all `xyzw` (values 0 through 3).
1170 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1171 [](int8_t c) { return c >= 0 && c <= 3; }));
1172
John Stiles9aeed132020-11-24 17:36:06 -05001173 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001174 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1175 // components don't actually matter since all fields are the same.
1176 ExpressionArray newArgs;
1177 newArgs.push_back(base.arguments().front()->clone());
1178 replacement = std::make_unique<Constructor>(
1179 base.fOffset,
1180 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1181 std::move(newArgs));
1182
John Stilesa60ac0c2020-12-22 08:59:51 -05001183 // We're replacing an expression with a cloned version; we'll need a rescan.
1184 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1185 // reference counts.
1186 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001187 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001188 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001189 break;
1190 }
1191
John Stiles0777ac42020-11-19 11:06:47 -05001192 // Swizzles can duplicate some elements and discard others, e.g.
1193 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1194 // - Expressions with side effects need to occur exactly once, even if they
1195 // would otherwise be swizzle-eliminated
1196 // - Non-trivial expressions should not be repeated, but elimination is OK.
1197 //
1198 // Look up the argument for the constructor at each index. This is typically simple
1199 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1200 // seems. This example would result in:
1201 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1202 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1203 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1204 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1205 struct ConstructorArgMap {
1206 int8_t fArgIndex;
1207 int8_t fComponent;
1208 };
1209
1210 int numConstructorArgs = base.type().columns();
1211 ConstructorArgMap argMap[4] = {};
1212 int writeIdx = 0;
1213 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1214 const Expression& expr = *base.arguments()[argIdx];
1215 int argWidth = expr.type().columns();
1216 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1217 argMap[writeIdx].fArgIndex = argIdx;
1218 argMap[writeIdx].fComponent = componentIdx;
1219 ++writeIdx;
1220 }
1221 }
1222 SkASSERT(writeIdx == numConstructorArgs);
1223
1224 // Count up the number of times each constructor argument is used by the
1225 // swizzle.
1226 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1227 // - bar.yz is referenced 3 times, by `.x_xy`
1228 // - half(foo) is referenced 1 time, by `._w__`
1229 int8_t exprUsed[4] = {};
1230 for (int c : s.components()) {
1231 exprUsed[argMap[c].fArgIndex]++;
1232 }
1233
1234 bool safeToOptimize = true;
1235 for (int index = 0; index < numConstructorArgs; ++index) {
1236 int8_t constructorArgIndex = argMap[index].fArgIndex;
1237 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1238
1239 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001240 if (exprUsed[constructorArgIndex] > 1 &&
1241 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001242 safeToOptimize = false;
1243 break;
1244 }
1245 // Check that side-effect-bearing expressions are swizzled in exactly once.
1246 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1247 safeToOptimize = false;
1248 break;
1249 }
1250 }
1251
1252 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001253 struct ReorderedArgument {
1254 int8_t fArgIndex;
1255 ComponentArray fComponents;
1256 };
1257 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001258 for (int c : s.components()) {
1259 const ConstructorArgMap& argument = argMap[c];
1260 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1261
John Stiles9aeed132020-11-24 17:36:06 -05001262 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001263 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001264 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001265 reorderedArgs.push_back({argument.fArgIndex,
1266 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001267 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001268 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001269 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001270 if (reorderedArgs.empty() ||
1271 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1272 // This can't be combined with the previous argument. Add a new one.
1273 reorderedArgs.push_back({argument.fArgIndex,
1274 ComponentArray{argument.fComponent}});
1275 } else {
1276 // Since we know this argument uses components, it should already
1277 // have at least one component set.
1278 SkASSERT(!reorderedArgs.back().fComponents.empty());
1279 // Build up the current argument with one more component.
1280 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1281 }
John Stiles0777ac42020-11-19 11:06:47 -05001282 }
1283 }
John Stilesd9076cb2020-11-19 12:18:36 -05001284
1285 // Convert our reordered argument list to an actual array of expressions, with
1286 // the new order and any new inner swizzles that need to be applied. Note that
1287 // we expect followup passes to clean up the inner swizzles.
1288 ExpressionArray newArgs;
1289 newArgs.reserve_back(swizzleSize);
1290 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1291 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1292 if (reorderedArg.fComponents.empty()) {
1293 newArgs.push_back(baseArg.clone());
1294 } else {
1295 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1296 reorderedArg.fComponents));
1297 }
1298 }
1299
1300 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001301 replacement = std::make_unique<Constructor>(
1302 base.fOffset,
1303 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1304 std::move(newArgs));
1305
John Stilesa60ac0c2020-12-22 08:59:51 -05001306 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001307 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001308
1309 // We're replacing an expression with a cloned version; we'll need a rescan.
1310 try_replace_expression(&b, iter, &replacement);
1311 optimizationContext->fUpdated = true;
1312 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001313 }
John Stiles108bbe22020-11-18 11:10:38 -05001314 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001315 }
John Stiles30212b72020-06-11 17:55:07 -04001316 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001317 }
1318 default:
1319 break;
1320 }
1321}
1322
John Stiles92219b42020-06-15 12:32:24 -04001323// Returns true if this statement could potentially execute a break at the current level. We ignore
1324// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001325static bool contains_conditional_break(Statement& stmt) {
1326 class ContainsConditionalBreak : public ProgramVisitor {
1327 public:
1328 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001329 switch (stmt.kind()) {
1330 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001331 return this->INHERITED::visitStatement(stmt);
1332
Ethan Nicholase6592142020-09-08 10:22:09 -04001333 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001334 return fInConditional > 0;
1335
Ethan Nicholase6592142020-09-08 10:22:09 -04001336 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001337 ++fInConditional;
1338 bool result = this->INHERITED::visitStatement(stmt);
1339 --fInConditional;
1340 return result;
1341 }
1342
1343 default:
1344 return false;
1345 }
1346 }
1347
1348 int fInConditional = 0;
1349 using INHERITED = ProgramVisitor;
1350 };
1351
1352 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001353}
1354
Ethan Nicholas5005a222018-08-24 13:06:27 -04001355// returns true if this statement definitely executes a break at the current level (we ignore
1356// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001357static bool contains_unconditional_break(Statement& stmt) {
1358 class ContainsUnconditionalBreak : public ProgramVisitor {
1359 public:
1360 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001361 switch (stmt.kind()) {
1362 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001363 return this->INHERITED::visitStatement(stmt);
1364
Ethan Nicholase6592142020-09-08 10:22:09 -04001365 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001366 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001367
1368 default:
1369 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001370 }
John Stilesb92641c2020-08-31 18:09:01 -04001371 }
John Stiles92219b42020-06-15 12:32:24 -04001372
John Stilesb92641c2020-08-31 18:09:01 -04001373 using INHERITED = ProgramVisitor;
1374 };
John Stiles92219b42020-06-15 12:32:24 -04001375
John Stilesb92641c2020-08-31 18:09:01 -04001376 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001377}
1378
John Stiles8f2a0cf2020-10-13 12:48:21 -04001379static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001380 switch (stmt->kind()) {
1381 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001382 // Recurse into the block.
1383 Block& block = static_cast<Block&>(*stmt);
1384
John Stiles8f2a0cf2020-10-13 12:48:21 -04001385 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001386 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001387 for (std::unique_ptr<Statement>& stmt : block.children()) {
1388 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001389 }
John Stiles92219b42020-06-15 12:32:24 -04001390
1391 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001392 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001393 break;
John Stiles92219b42020-06-15 12:32:24 -04001394 }
1395
Ethan Nicholase6592142020-09-08 10:22:09 -04001396 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001397 // Do not append a break to the target.
1398 break;
1399
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001400 default:
John Stiles92219b42020-06-15 12:32:24 -04001401 // Append normal statements to the target.
1402 target->push_back(std::move(stmt));
1403 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001404 }
1405}
1406
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001407// Returns a block containing all of the statements that will be run if the given case matches
1408// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1409// broken by this call and must then be discarded).
1410// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1411// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001412static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1413 SwitchCase* caseToCapture) {
1414 // We have to be careful to not move any of the pointers until after we're sure we're going to
1415 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1416 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001417 auto iter = switchStatement->cases().begin();
1418 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001419 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001420 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001421 }
John Stiles92219b42020-06-15 12:32:24 -04001422 }
1423
1424 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1425 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1426 // statements that we can use for simplification.
1427 auto startIter = iter;
1428 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001429 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001430 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001431 if (contains_conditional_break(*stmt)) {
1432 // We can't reduce switch-cases to a block when they have conditional breaks.
1433 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001434 }
John Stiles92219b42020-06-15 12:32:24 -04001435
1436 if (contains_unconditional_break(*stmt)) {
1437 // We found an unconditional break. We can use this block, but we need to strip
1438 // out the break statement.
1439 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001440 break;
1441 }
1442 }
John Stiles92219b42020-06-15 12:32:24 -04001443
1444 if (unconditionalBreakStmt != nullptr) {
1445 break;
1446 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001447 }
John Stiles92219b42020-06-15 12:32:24 -04001448
1449 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1450 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001451 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001452
1453 // We can move over most of the statements as-is.
1454 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001455 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001456 caseStmts.push_back(std::move(stmt));
1457 }
1458 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001459 }
John Stiles92219b42020-06-15 12:32:24 -04001460
1461 // If we found an unconditional break at the end, we need to move what we can while avoiding
1462 // that break.
1463 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001464 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001465 if (stmt.get() == unconditionalBreakStmt) {
1466 move_all_but_break(stmt, &caseStmts);
1467 unconditionalBreakStmt = nullptr;
1468 break;
1469 }
1470
1471 caseStmts.push_back(std::move(stmt));
1472 }
1473 }
1474
1475 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1476
1477 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001478 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001479}
1480
Ethan Nicholascb670962017-04-20 19:31:52 -04001481void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001482 BasicBlock& b,
1483 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001484 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001485 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001486 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001487 switch (stmt->kind()) {
1488 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001489 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001490 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001491 (!varDecl.value() ||
1492 !varDecl.value()->hasSideEffects())) {
1493 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001494 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001495 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001496 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001497 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001498 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001499 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001500 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001501 }
1502 break;
1503 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001504 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001505 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001506 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001507 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001508 if (i.test()->as<BoolLiteral>().value()) {
1509 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001510 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001511 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001512 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001513 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001514 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001515 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001516 }
1517 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001518 optimizationContext->fUpdated = true;
1519 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001520 break;
1521 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001522 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001523 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001524 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001525 optimizationContext->fUpdated = true;
1526 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001527 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001528 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001529 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001530 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001531 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001532 (*iter)->setStatement(
1533 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001534 } else {
1535 // no if, no else, no test side effects, kill the whole if
1536 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001537 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001538 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001539 optimizationContext->fUpdated = true;
1540 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001541 }
1542 break;
1543 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001544 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001545 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001546 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001547 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001548 // switch is constant, replace it with the case that matches
1549 bool found = false;
1550 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001551 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1552 if (!c->value()) {
1553 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001554 continue;
1555 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001556 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001557 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001558 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001559 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001560 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001561 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001562 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001563 break;
1564 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001565 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1566 optimizationContext->fSilences.find(&s) ==
1567 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001568 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001569 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001570 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001571 }
1572 return; // can't simplify
1573 }
1574 }
1575 }
1576 if (!found) {
1577 // no matching case. use default if it exists, or kill the whole thing
1578 if (defaultCase) {
1579 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1580 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001581 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001582 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001583 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1584 optimizationContext->fSilences.find(&s) ==
1585 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001586 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001587 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001588 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001589 }
1590 return; // can't simplify
1591 }
1592 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001593 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001594 }
1595 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001596 optimizationContext->fUpdated = true;
1597 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001598 }
1599 break;
1600 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001601 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001602 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001603 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001604 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001605 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001606 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001607 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001608 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001609 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001610 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001611 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001612 }
1613 break;
1614 }
1615 default:
1616 break;
1617 }
1618}
1619
Brian Osman010ce6a2020-10-19 16:34:10 -04001620bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001621 bool madeChanges = false;
1622
Ethan Nicholascb670962017-04-20 19:31:52 -04001623 CFG cfg = CFGGenerator().getCFG(f);
1624 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001625
1626 // check for unreachable code
1627 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001628 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001629 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001630 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001631 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001632 if (node.isStatement()) {
1633 offset = (*node.statement())->fOffset;
1634 } else {
1635 offset = (*node.expression())->fOffset;
1636 if ((*node.expression())->is<BoolLiteral>()) {
1637 // Function inlining can generate do { ... } while(false) loops which always
1638 // break, so the boolean condition is considered unreachable. Since not being
1639 // able to reach a literal is a non-issue in the first place, we don't report an
1640 // error in this case.
1641 continue;
1642 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001643 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001644 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001645 }
1646 }
1647 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001648 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001649 }
1650
Ethan Nicholascb670962017-04-20 19:31:52 -04001651 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001652 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001653 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001654 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001655 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001656 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001657 cfg = CFGGenerator().getCFG(f);
1658 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001659 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001660 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001661
John Stiles7d3f0892020-11-03 11:35:01 -05001662 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001663 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001664
1665 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1666 if (eliminatedBlockIds.test(blockId)) {
1667 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1668 optimizationContext.fUpdated = true;
1669 optimizationContext.fNeedsRescan = true;
1670 break;
1671 }
1672
1673 BasicBlock& b = cfg.fBlocks[blockId];
1674 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001675 // Block was reachable before optimization, but has since become unreachable. In
1676 // addition to being dead code, it's broken - since control flow can't reach it, no
1677 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001678 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001679 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001680 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001681 // Eliminating a node runs the risk of eliminating that node's exits as
1682 // well. Keep track of this and do a rescan if we are about to access one
1683 // of these.
1684 for (BlockId id : b.fExits) {
1685 eliminatedBlockIds.set(id);
1686 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001687 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001688 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001689 }
1690 }
1691 continue;
1692 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001693 DefinitionMap definitions = b.fBefore;
1694
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001695 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1696 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001697 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001698 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001699 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001700 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001701 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001702 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001703 break;
1704 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001705 this->addDefinitions(*iter, &definitions);
1706 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001707
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001708 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001709 break;
1710 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001711 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001712 madeChanges |= optimizationContext.fUpdated;
1713 } while (optimizationContext.fUpdated);
1714 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001715
Ethan Nicholas91a10532017-06-22 11:24:38 -04001716 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001717 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001718 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1719 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001720 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001721 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001722 switch (s.kind()) {
1723 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001724 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001725 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001726 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001727 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001728 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001729 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001730 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001731 if (s.as<SwitchStatement>().isStatic() &&
1732 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1733 optimizationContext.fSilences.find(&s) ==
1734 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001735 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001736 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001737 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001738 break;
1739 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001740 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001741 break;
1742 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001743 } else {
1744 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001745 }
1746 }
1747 }
1748
ethannicholas22f939e2016-10-13 13:25:34 -07001749 // check for missing return
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001750 if (f.declaration().returnType() != *fContext->fVoid_Type) {
John Stiles61e75e32020-10-01 15:42:37 -04001751 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001752 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001753 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001754 }
1755 }
John Stiles0cc193a2020-09-09 09:39:34 -04001756
1757 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001758}
1759
Brian Osman32d53552020-09-23 13:55:20 -04001760std::unique_ptr<Program> Compiler::convertProgram(
1761 Program::Kind kind,
1762 String text,
1763 const Program::Settings& settings,
1764 const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
1765 SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001766
Brian Osman0006ad02020-11-18 15:38:39 -05001767 // Loading and optimizing our base module might reset the inliner, so do that first,
1768 // *then* configure the inliner with the settings for this program.
1769 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1770
ethannicholasb3058bd2016-07-01 08:22:01 -07001771 fErrorText = "";
1772 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001773 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001774
1775 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001776 std::unique_ptr<String> textPtr(new String(std::move(text)));
1777 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001778
John Stiles5c7bb322020-10-22 11:09:15 -04001779 // Enable node pooling while converting and optimizing the program for a performance boost.
1780 // The Program will take ownership of the pool.
John Stiles2d68ea32020-10-22 15:42:27 -04001781 std::unique_ptr<Pool> pool = Pool::Create();
1782 pool->attachToThread();
Brian Osman0006ad02020-11-18 15:38:39 -05001783 IRGenerator::IRBundle ir =
1784 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
1785 textPtr->c_str(), textPtr->size(), externalValues);
John Stiles5c7bb322020-10-22 11:09:15 -04001786 auto program = std::make_unique<Program>(kind,
1787 std::move(textPtr),
1788 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001789 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001790 fContext,
1791 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001792 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001793 std::move(ir.fModifiers),
1794 std::move(ir.fSymbolTable),
1795 std::move(pool),
1796 ir.fInputs);
1797 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001798 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001799 // Do not return programs that failed to compile.
1800 } else if (settings.fOptimize && !this->optimize(*program)) {
1801 // Do not return programs that failed to optimize.
1802 } else {
1803 // We have a successful program!
1804 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001805 }
John Stiles5c7bb322020-10-22 11:09:15 -04001806
1807 program->fPool->detachFromThread();
1808 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001809}
1810
Brian Osman0006ad02020-11-18 15:38:39 -05001811bool Compiler::optimize(LoadedModule& module) {
1812 SkASSERT(!fErrorCount);
1813 Program::Settings settings;
1814 fIRGenerator->fKind = module.fKind;
1815 fIRGenerator->fSettings = &settings;
1816 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1817
1818 fInliner.reset(fModifiers.back().get(), &settings);
1819
1820 while (fErrorCount == 0) {
1821 bool madeChanges = false;
1822
1823 // Scan and optimize based on the control-flow graph for each function.
1824 for (const auto& element : module.fElements) {
1825 if (element->is<FunctionDefinition>()) {
1826 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1827 }
1828 }
1829
1830 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001831 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001832
1833 if (!madeChanges) {
1834 break;
1835 }
1836 }
1837 return fErrorCount == 0;
1838}
1839
Ethan Nicholas00543112018-07-31 09:44:36 -04001840bool Compiler::optimize(Program& program) {
1841 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001842 fIRGenerator->fKind = program.fKind;
1843 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001844 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001845
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001846 while (fErrorCount == 0) {
1847 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001848
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001849 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001850 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001851 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001852 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001853 }
1854 }
1855
1856 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001857 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001858
1859 // Remove dead functions. We wait until after analysis so that we still report errors,
1860 // even in unused code.
1861 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001862 auto isDeadFunction = [&](const ProgramElement* element) {
1863 if (!element->is<FunctionDefinition>()) {
1864 return false;
1865 }
1866 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1867 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1868 usage->remove(*element);
1869 madeChanges = true;
1870 return true;
1871 }
1872 return false;
1873 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001874 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001875 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001876 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001877 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001878 }),
1879 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001880 program.fSharedElements.erase(
1881 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1882 isDeadFunction),
1883 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001884 }
1885
1886 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001887 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001888 auto isDeadVariable = [&](const ProgramElement* element) {
1889 if (!element->is<GlobalVarDeclaration>()) {
1890 return false;
1891 }
1892 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1893 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1894 if (usage->isDead(varDecl.var())) {
1895 madeChanges = true;
1896 return true;
1897 }
1898 return false;
1899 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001900 program.fElements.erase(
1901 std::remove_if(program.fElements.begin(), program.fElements.end(),
1902 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001903 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001904 }),
1905 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001906 program.fSharedElements.erase(
1907 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1908 isDeadVariable),
1909 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001910 }
John Stiles73a6bff2020-09-09 13:40:37 -04001911
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001912 if (!madeChanges) {
1913 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001914 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001915 }
1916 return fErrorCount == 0;
1917}
1918
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001919#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1920
Ethan Nicholas00543112018-07-31 09:44:36 -04001921bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001922#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001923 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001924 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001925 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001926 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001927 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001928 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001929 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001930 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001931 String errors;
1932 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1933 const char* m) {
1934 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001935 };
1936 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001937
1938 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1939 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1940 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1941 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1942
1943 if (!result) {
1944#if defined(SKSL_STANDALONE)
1945 // Convert the string-stream to a SPIR-V disassembly.
1946 std::string disassembly;
1947 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1948 errors.append(disassembly);
1949 }
1950 this->error(-1, errors);
1951#else
1952 SkDEBUGFAILF("%s", errors.c_str());
1953#endif
1954 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001955 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001956 }
1957#else
Brian Osman88cda172020-10-09 12:05:16 -04001958 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001959 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001960 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001961#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001962 return result;
1963}
1964
Ethan Nicholas00543112018-07-31 09:44:36 -04001965bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001966 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001967 bool result = this->toSPIRV(program, buffer);
1968 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001969 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001970 }
1971 return result;
1972}
1973
Ethan Nicholas00543112018-07-31 09:44:36 -04001974bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001975 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001976 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001977 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001978 return result;
1979}
1980
Ethan Nicholas00543112018-07-31 09:44:36 -04001981bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001982 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001983 bool result = this->toGLSL(program, buffer);
1984 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001985 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001986 }
1987 return result;
1988}
1989
Brian Osmanc0243912020-02-19 15:35:26 -05001990bool Compiler::toHLSL(Program& program, String* out) {
1991 String spirv;
1992 if (!this->toSPIRV(program, &spirv)) {
1993 return false;
1994 }
1995
1996 return SPIRVtoHLSL(spirv, out);
1997}
1998
Ethan Nicholas00543112018-07-31 09:44:36 -04001999bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002000 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04002001 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04002002 return result;
2003}
2004
Ethan Nicholas00543112018-07-31 09:44:36 -04002005bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04002006 StringStream buffer;
2007 bool result = this->toMetal(program, buffer);
2008 if (result) {
2009 *out = buffer.str();
2010 }
2011 return result;
2012}
2013
Greg Daniela28ea672020-09-25 11:12:56 -04002014#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002015bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002016 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002017 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002018 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04002019 return result;
2020}
2021
Ethan Nicholas00543112018-07-31 09:44:36 -04002022bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002023 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002024 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002025 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002026 return result;
2027}
Greg Daniela28ea672020-09-25 11:12:56 -04002028#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002029
Ethan Nicholas2a479a52020-08-18 16:29:45 -04002030#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04002031
2032#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04002033bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04002034 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04002035 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05002036 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04002037 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002038 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05002039 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04002040 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04002041 return result;
2042}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04002043#endif
2044
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002045std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Brian Osman88cda172020-10-09 12:05:16 -04002046 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002047 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04002048 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
2049 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04002050 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002051 return result;
2052 }
2053 return nullptr;
2054}
2055
Brian Osman401a0092020-09-10 14:47:24 -04002056const char* Compiler::OperatorName(Token::Kind op) {
2057 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002058 case Token::Kind::TK_PLUS: return "+";
2059 case Token::Kind::TK_MINUS: return "-";
2060 case Token::Kind::TK_STAR: return "*";
2061 case Token::Kind::TK_SLASH: return "/";
2062 case Token::Kind::TK_PERCENT: return "%";
2063 case Token::Kind::TK_SHL: return "<<";
2064 case Token::Kind::TK_SHR: return ">>";
2065 case Token::Kind::TK_LOGICALNOT: return "!";
2066 case Token::Kind::TK_LOGICALAND: return "&&";
2067 case Token::Kind::TK_LOGICALOR: return "||";
2068 case Token::Kind::TK_LOGICALXOR: return "^^";
2069 case Token::Kind::TK_BITWISENOT: return "~";
2070 case Token::Kind::TK_BITWISEAND: return "&";
2071 case Token::Kind::TK_BITWISEOR: return "|";
2072 case Token::Kind::TK_BITWISEXOR: return "^";
2073 case Token::Kind::TK_EQ: return "=";
2074 case Token::Kind::TK_EQEQ: return "==";
2075 case Token::Kind::TK_NEQ: return "!=";
2076 case Token::Kind::TK_LT: return "<";
2077 case Token::Kind::TK_GT: return ">";
2078 case Token::Kind::TK_LTEQ: return "<=";
2079 case Token::Kind::TK_GTEQ: return ">=";
2080 case Token::Kind::TK_PLUSEQ: return "+=";
2081 case Token::Kind::TK_MINUSEQ: return "-=";
2082 case Token::Kind::TK_STAREQ: return "*=";
2083 case Token::Kind::TK_SLASHEQ: return "/=";
2084 case Token::Kind::TK_PERCENTEQ: return "%=";
2085 case Token::Kind::TK_SHLEQ: return "<<=";
2086 case Token::Kind::TK_SHREQ: return ">>=";
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002087 case Token::Kind::TK_BITWISEANDEQ: return "&=";
2088 case Token::Kind::TK_BITWISEOREQ: return "|=";
2089 case Token::Kind::TK_BITWISEXOREQ: return "^=";
2090 case Token::Kind::TK_PLUSPLUS: return "++";
2091 case Token::Kind::TK_MINUSMINUS: return "--";
2092 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002093 default:
Brian Osman401a0092020-09-10 14:47:24 -04002094 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002095 }
2096}
2097
2098
2099bool Compiler::IsAssignment(Token::Kind op) {
2100 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002101 case Token::Kind::TK_EQ: // fall through
2102 case Token::Kind::TK_PLUSEQ: // fall through
2103 case Token::Kind::TK_MINUSEQ: // fall through
2104 case Token::Kind::TK_STAREQ: // fall through
2105 case Token::Kind::TK_SLASHEQ: // fall through
2106 case Token::Kind::TK_PERCENTEQ: // fall through
2107 case Token::Kind::TK_SHLEQ: // fall through
2108 case Token::Kind::TK_SHREQ: // fall through
2109 case Token::Kind::TK_BITWISEOREQ: // fall through
2110 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05002111 case Token::Kind::TK_BITWISEANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002112 return true;
2113 default:
2114 return false;
2115 }
2116}
2117
Brian Osman401a0092020-09-10 14:47:24 -04002118Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
2119 switch (op) {
2120 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
2121 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
2122 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
2123 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
2124 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
2125 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
2126 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
2127 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
2128 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
2129 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
Brian Osman401a0092020-09-10 14:47:24 -04002130 default: return op;
2131 }
2132}
2133
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002134Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05002135 if (fSource && offset >= 0) {
2136 int line = 1;
2137 int column = 1;
2138 for (int i = 0; i < offset; i++) {
2139 if ((*fSource)[i] == '\n') {
2140 ++line;
2141 column = 1;
2142 }
2143 else {
2144 ++column;
2145 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002146 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05002147 return Position(line, column);
2148 } else {
2149 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002150 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002151}
2152
2153void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002154 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002155 Position pos = this->position(offset);
Ethan Nicholas3c729892020-12-07 12:47:17 -05002156 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07002157}
2158
Ethan Nicholasdcd2f862020-12-17 23:24:25 +00002159String Compiler::errorText() {
2160 this->writeErrorCount();
Ethan Nicholas00543112018-07-31 09:44:36 -04002161 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002162 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07002163 return result;
2164}
2165
2166void Compiler::writeErrorCount() {
2167 if (fErrorCount) {
2168 fErrorText += to_string(fErrorCount) + " error";
2169 if (fErrorCount > 1) {
2170 fErrorText += "s";
2171 }
2172 fErrorText += "\n";
2173 }
2174}
2175
John Stilesa6841be2020-08-06 14:11:56 -04002176} // namespace SkSL