blob: 69de03f249270a66c668033dac7aa85014fdd006 [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 Osmanc0f2b642020-12-22 13:35:55 -0500113 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500114
Brian Osmanb06301e2020-11-06 11:45:36 -0500115 TYPE(Half2x2), TYPE(Half2x3), TYPE(Half2x4),
116 TYPE(Half3x2), TYPE(Half3x3), TYPE(Half3x4),
117 TYPE(Half4x2), TYPE(Half4x3), TYPE(Half4x4),
ethannicholasb3058bd2016-07-01 08:22:01 -0700118
Brian Osmanb06301e2020-11-06 11:45:36 -0500119 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenUType), TYPE(GenBType),
Brian Osmanc0f2b642020-12-22 13:35:55 -0500120 TYPE(SquareMat), TYPE(SquareHMat), TYPE(Vec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500121 TYPE(HVec), TYPE(IVec), TYPE(UVec), TYPE(SVec), TYPE(USVec),
122 TYPE(ByteVec), TYPE(UByteVec), TYPE(BVec),
123
124 TYPE(FragmentProcessor),
125 };
126
127 const SkSL::Symbol* privateTypes[] = {
Brian Osmanc0f2b642020-12-22 13:35:55 -0500128 TYPE(Float2x3), TYPE(Float2x4),
129 TYPE(Float3x2), TYPE(Float3x4),
130 TYPE(Float4x2), TYPE(Float4x3),
131
132 TYPE(Mat), TYPE(HMat),
133
Brian Osmanb06301e2020-11-06 11:45:36 -0500134 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
135 TYPE(SamplerExternalOES),
136 TYPE(SamplerCube),
137 TYPE(Sampler2DRect),
138 TYPE(Sampler1DArray), TYPE(Sampler2DArray), TYPE(SamplerCubeArray),
139 TYPE(SamplerBuffer),
140 TYPE(Sampler2DMS), TYPE(Sampler2DMSArray),
141
142 TYPE(ISampler2D),
143 TYPE(Image2D), TYPE(IImage2D),
144 TYPE(SubpassInput), TYPE(SubpassInputMS),
145
Brian Osmanb06301e2020-11-06 11:45:36 -0500146 TYPE(Sampler1DShadow), TYPE(Sampler2DShadow), TYPE(SamplerCubeShadow),
147 TYPE(Sampler2DRectShadow),
148 TYPE(Sampler1DArrayShadow), TYPE(Sampler2DArrayShadow), TYPE(SamplerCubeArrayShadow),
149
Brian Osmanb06301e2020-11-06 11:45:36 -0500150 TYPE(Sampler),
151 TYPE(Texture2D),
152 };
153
154 for (const SkSL::Symbol* type : rootTypes) {
155 fRootSymbolTable->addWithoutOwnership(type);
156 }
157 for (const SkSL::Symbol* type : privateTypes) {
158 fPrivateSymbolTable->addWithoutOwnership(type);
159 }
160
161#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700162
Brian Osman3887a012020-09-30 13:22:27 -0400163 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
164 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500165 fPrivateSymbolTable->add(
166 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500167 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500168 "sk_Caps",
169 fContext->fSkCaps_Type.get(),
170 /*builtin=*/false,
171 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500172
Brian Osman3d87e9f2020-10-08 11:50:22 -0400173 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500174 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700175}
176
John Stilesdd13dba2020-10-29 10:45:34 -0400177Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700178
Brian Osman56269982020-11-20 12:38:07 -0500179const ParsedModule& Compiler::loadGPUModule() {
180 if (!fGPUModule.fSymbols) {
181 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
182 }
183 return fGPUModule;
184}
185
186const ParsedModule& Compiler::loadFragmentModule() {
187 if (!fFragmentModule.fSymbols) {
188 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag),
189 this->loadGPUModule());
190 }
191 return fFragmentModule;
192}
193
194const ParsedModule& Compiler::loadVertexModule() {
195 if (!fVertexModule.fSymbols) {
196 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert),
197 this->loadGPUModule());
198 }
199 return fVertexModule;
200}
201
Brian Osman88cda172020-10-09 12:05:16 -0400202const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400203 if (!fGeometryModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500204 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom),
205 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400206 }
Brian Osman88cda172020-10-09 12:05:16 -0400207 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400208}
209
Brian Osman88cda172020-10-09 12:05:16 -0400210const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400211 if (!fFPModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500212 fFPModule = this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp),
213 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400214 }
Brian Osman88cda172020-10-09 12:05:16 -0400215 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400216}
217
Brian Osmanb06301e2020-11-06 11:45:36 -0500218const ParsedModule& Compiler::loadPublicModule() {
219 if (!fPublicModule.fSymbols) {
220 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
221 }
222 return fPublicModule;
223}
224
Brian Osman91946752020-12-21 13:20:40 -0500225const ParsedModule& Compiler::loadRuntimeEffectModule() {
226 if (!fRuntimeEffectModule.fSymbols) {
227 fRuntimeEffectModule = this->parseModule(Program::kRuntimeEffect_Kind, MODULE_DATA(runtime),
228 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400229
Brian Osman91946752020-12-21 13:20:40 -0500230 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
231 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fFragmentProcessor_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400232
Brian Osman91946752020-12-21 13:20:40 -0500233 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fFloat2_Type.get());
234 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fFloat3_Type.get());
235 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fFloat4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400236
Brian Osman91946752020-12-21 13:20:40 -0500237 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fBool2_Type.get());
238 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fBool3_Type.get());
239 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fBool4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400240
Brian Osman91946752020-12-21 13:20:40 -0500241 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fFloat2x2_Type.get());
242 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fFloat3x3_Type.get());
243 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fFloat4x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400244
Brian Osman91946752020-12-21 13:20:40 -0500245 fRuntimeEffectModule.fSymbols->addAlias("mat2x2", fContext->fFloat2x2_Type.get());
246 fRuntimeEffectModule.fSymbols->addAlias("mat2x3", fContext->fFloat2x3_Type.get());
247 fRuntimeEffectModule.fSymbols->addAlias("mat2x4", fContext->fFloat2x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400248
Brian Osman91946752020-12-21 13:20:40 -0500249 fRuntimeEffectModule.fSymbols->addAlias("mat3x2", fContext->fFloat3x2_Type.get());
250 fRuntimeEffectModule.fSymbols->addAlias("mat3x3", fContext->fFloat3x3_Type.get());
251 fRuntimeEffectModule.fSymbols->addAlias("mat3x4", fContext->fFloat3x4_Type.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400252
Brian Osman91946752020-12-21 13:20:40 -0500253 fRuntimeEffectModule.fSymbols->addAlias("mat4x2", fContext->fFloat4x2_Type.get());
254 fRuntimeEffectModule.fSymbols->addAlias("mat4x3", fContext->fFloat4x3_Type.get());
255 fRuntimeEffectModule.fSymbols->addAlias("mat4x4", fContext->fFloat4x4_Type.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400256 }
Brian Osman91946752020-12-21 13:20:40 -0500257 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400258}
259
Brian Osman88cda172020-10-09 12:05:16 -0400260const ParsedModule& Compiler::loadInterpreterModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400261 if (!fInterpreterModule.fSymbols) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500262 fInterpreterModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(interp),
263 this->loadPublicModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400264 }
Brian Osman88cda172020-10-09 12:05:16 -0400265 return fInterpreterModule;
266}
267
268const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
269 switch (kind) {
Brian Osman91946752020-12-21 13:20:40 -0500270 case Program::kVertex_Kind: return this->loadVertexModule(); break;
271 case Program::kFragment_Kind: return this->loadFragmentModule(); break;
272 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
273 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
274 case Program::kRuntimeEffect_Kind: return this->loadRuntimeEffectModule(); break;
275 case Program::kGeneric_Kind: return this->loadInterpreterModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400276 }
277 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400278}
279
Brian Osman3d87e9f2020-10-08 11:50:22 -0400280LoadedModule Compiler::loadModule(Program::Kind kind,
281 ModuleData data,
282 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400283 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500284 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
285 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
286 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
287 // like samplers or textures. Today, 'Private' does contain the union of all known types,
288 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
289 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
290 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400291 }
292
293#if defined(SKSL_STANDALONE)
294 SkASSERT(data.fPath);
295 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400296 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
297 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400298 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400299 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400300 abort();
301 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400302 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400303 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400304 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400305 SkASSERT(fIRGenerator->fCanInline);
306 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400307 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500308 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500309 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500310 /*isBuiltinCode=*/true, source->c_str(), source->length(),
311 /*externalValues=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400312 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500313 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400314 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400315 if (this->fErrorCount) {
316 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400317 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400318 }
Brian Osman88cda172020-10-09 12:05:16 -0400319 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400320#else
321 SkASSERT(data.fData && (data.fSize != 0));
322 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
323 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500324 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400325 fModifiers.push_back(fIRGenerator->releaseModifiers());
326#endif
327
328 return module;
329}
330
331ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500332 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
333 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400334
335 // For modules that just declare (but don't define) intrinsic functions, there will be no new
336 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500337 if (module.fElements.empty()) {
338 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400339 }
340
341 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
342
343 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
344 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500345 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400346 switch (element->kind()) {
347 case ProgramElement::Kind::kFunction: {
348 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400349 SkASSERT(f.declaration().isBuiltin());
350 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400351 break;
352 }
John Stiles569249b2020-11-03 12:18:22 -0500353 case ProgramElement::Kind::kFunctionPrototype: {
354 // These are already in the symbol table.
355 break;
356 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400357 case ProgramElement::Kind::kEnum: {
358 const Enum& e = element->as<Enum>();
359 SkASSERT(e.isBuiltin());
360 intrinsics->insertOrDie(e.typeName(), std::move(element));
361 break;
362 }
363 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400364 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
365 const Variable& var = global.declaration()->as<VarDeclaration>().var();
366 SkASSERT(var.isBuiltin());
367 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400368 break;
369 }
370 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400371 const Variable& var = element->as<InterfaceBlock>().variable();
372 SkASSERT(var.isBuiltin());
373 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400374 break;
375 }
376 default:
377 printf("Unsupported element: %s\n", element->description().c_str());
378 SkASSERT(false);
379 break;
380 }
381 }
382
Brian Osman0006ad02020-11-18 15:38:39 -0500383 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400384}
385
ethannicholas22f939e2016-10-13 13:25:34 -0700386// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500387void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
388 DefinitionMap* definitions) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400389 switch (lvalue->kind()) {
390 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -0400391 const Variable& var = *lvalue->as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400392 if (var.storage() == Variable::Storage::kLocal) {
John Stiles796cdb72020-10-08 12:06:53 -0400393 definitions->set(&var, expr);
ethannicholas22f939e2016-10-13 13:25:34 -0700394 }
395 break;
396 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400397 case Expression::Kind::kSwizzle:
ethannicholas22f939e2016-10-13 13:25:34 -0700398 // We consider the variable written to as long as at least some of its components have
399 // been written to. This will lead to some false negatives (we won't catch it if you
400 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400401 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
402 // 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 -0700403 // more complicated whole-program analysis. This is probably good enough.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400404 this->addDefinition(lvalue->as<Swizzle>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400405 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700406 definitions);
407 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400408 case Expression::Kind::kIndex:
ethannicholas22f939e2016-10-13 13:25:34 -0700409 // see comments in Swizzle
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400410 this->addDefinition(lvalue->as<IndexExpression>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400411 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700412 definitions);
413 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400414 case Expression::Kind::kFieldAccess:
ethannicholas22f939e2016-10-13 13:25:34 -0700415 // see comments in Swizzle
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400416 this->addDefinition(lvalue->as<FieldAccess>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400417 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700418 definitions);
419 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400420 case Expression::Kind::kTernary:
Ethan Nicholasa583b812018-01-18 13:32:11 -0500421 // To simplify analysis, we just pretend that we write to both sides of the ternary.
422 // This allows for false positives (meaning we fail to detect that a variable might not
423 // have been assigned), but is preferable to false negatives.
Ethan Nicholasdd218162020-10-08 05:48:01 -0400424 this->addDefinition(lvalue->as<TernaryExpression>().ifTrue().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400425 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500426 definitions);
Ethan Nicholasdd218162020-10-08 05:48:01 -0400427 this->addDefinition(lvalue->as<TernaryExpression>().ifFalse().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400428 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500429 definitions);
430 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400431 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400432 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700433 default:
434 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400435 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700436 }
437}
438
439// add local variables defined by this node to the set
John Stiles796cdb72020-10-08 12:06:53 -0400440void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) {
John Stiles70025e52020-09-28 16:08:58 -0400441 if (node.isExpression()) {
442 Expression* expr = node.expression()->get();
443 switch (expr->kind()) {
444 case Expression::Kind::kBinary: {
445 BinaryExpression* b = &expr->as<BinaryExpression>();
446 if (b->getOperator() == Token::Kind::TK_EQ) {
John Stiles2d4f9592020-10-30 10:29:12 -0400447 this->addDefinition(b->left().get(), &b->right(), definitions);
John Stiles70025e52020-09-28 16:08:58 -0400448 } else if (Compiler::IsAssignment(b->getOperator())) {
449 this->addDefinition(
John Stiles2d4f9592020-10-30 10:29:12 -0400450 b->left().get(),
John Stiles70025e52020-09-28 16:08:58 -0400451 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
452 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500453
ethannicholas22f939e2016-10-13 13:25:34 -0700454 }
John Stiles70025e52020-09-28 16:08:58 -0400455 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700456 }
John Stiles70025e52020-09-28 16:08:58 -0400457 case Expression::Kind::kFunctionCall: {
458 const FunctionCall& c = expr->as<FunctionCall>();
Brian Osman5bf3e202020-10-13 10:34:18 -0400459 const std::vector<const Variable*>& parameters = c.function().parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400460 for (size_t i = 0; i < parameters.size(); ++i) {
461 if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stiles70025e52020-09-28 16:08:58 -0400462 this->addDefinition(
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400463 c.arguments()[i].get(),
John Stiles70025e52020-09-28 16:08:58 -0400464 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
465 definitions);
466 }
467 }
468 break;
469 }
470 case Expression::Kind::kPrefix: {
471 const PrefixExpression* p = &expr->as<PrefixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400472 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
473 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400474 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400475 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400476 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
477 definitions);
478 }
479 break;
480 }
481 case Expression::Kind::kPostfix: {
482 const PostfixExpression* p = &expr->as<PostfixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400483 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
484 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400485 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400486 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400487 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
488 definitions);
489 }
490 break;
491 }
492 case Expression::Kind::kVariableReference: {
493 const VariableReference* v = &expr->as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400494 if (v->refKind() != VariableReference::RefKind::kRead) {
John Stiles70025e52020-09-28 16:08:58 -0400495 this->addDefinition(
496 v,
497 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
498 definitions);
499 }
500 break;
501 }
502 default:
503 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700504 }
John Stiles70025e52020-09-28 16:08:58 -0400505 } else if (node.isStatement()) {
506 Statement* stmt = node.statement()->get();
507 if (stmt->is<VarDeclaration>()) {
508 VarDeclaration& vd = stmt->as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400509 if (vd.value()) {
510 definitions->set(&vd.var(), &vd.value());
ethannicholas22f939e2016-10-13 13:25:34 -0700511 }
ethannicholas22f939e2016-10-13 13:25:34 -0700512 }
513 }
514}
515
John Stilese6150002020-10-05 12:03:53 -0400516void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700517 BasicBlock& block = cfg->fBlocks[blockId];
518
519 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500520 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700521 for (const BasicBlock::Node& n : block.fNodes) {
522 this->addDefinitions(n, &after);
523 }
524
525 // propagate definitions to exits
526 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400527 if (exitId == blockId) {
528 continue;
529 }
ethannicholas22f939e2016-10-13 13:25:34 -0700530 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500531 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400532 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
533 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400534 // exit has no definition for it, just copy it and reprocess exit block
535 processedSet->reset(exitId);
John Stiles796cdb72020-10-08 12:06:53 -0400536 exit.fBefore[var] = e1;
ethannicholas22f939e2016-10-13 13:25:34 -0700537 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500538 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400539 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700540 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400541 // definition has changed, merge and reprocess the exit block
542 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500543 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400544 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500545 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400546 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500547 }
ethannicholas22f939e2016-10-13 13:25:34 -0700548 }
549 }
John Stiles65b48272020-12-22 17:18:34 -0500550 }
ethannicholas22f939e2016-10-13 13:25:34 -0700551 }
552}
553
554// returns a map which maps all local variables in the function to null, indicating that their value
555// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500556static DefinitionMap compute_start_state(const CFG& cfg) {
557 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400558 for (const auto& block : cfg.fBlocks) {
559 for (const auto& node : block.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -0400560 if (node.isStatement()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400561 const Statement* s = node.statement()->get();
Brian Osmanc0213602020-10-06 14:43:32 -0400562 if (s->is<VarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400563 result[&s->as<VarDeclaration>().var()] = nullptr;
ethannicholas22f939e2016-10-13 13:25:34 -0700564 }
565 }
566 }
567 }
568 return result;
569}
570
Ethan Nicholascb670962017-04-20 19:31:52 -0400571/**
572 * Returns true if assigning to this lvalue has no effect.
573 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400574static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400575 switch (lvalue.kind()) {
576 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400577 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400578 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400579 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400580 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400581 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400582 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400583 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400584 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400585 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400586 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400587 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400588 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400589 return !t.test()->hasSideEffects() &&
590 is_dead(*t.ifTrue(), usage) &&
591 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500592 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400593 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400594 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400595 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500596#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400597 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500598#endif
599 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400600 }
601}
ethannicholas22f939e2016-10-13 13:25:34 -0700602
Ethan Nicholascb670962017-04-20 19:31:52 -0400603/**
604 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
605 * to a dead target and lack of side effects on the left hand side.
606 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400607static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400608 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400609 return false;
610 }
John Stiles2d4f9592020-10-30 10:29:12 -0400611 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400612}
613
614void Compiler::computeDataFlow(CFG* cfg) {
615 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400616
617 // We set bits in the "processed" set after a block has been scanned.
618 SkBitSet processedSet(cfg->fBlocks.size());
619 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
620 processedSet.set(*blockId);
621 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700622 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400623}
624
625/**
626 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
627 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
628 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
629 * need to be regenerated).
630 */
John Stilesafbf8992020-08-18 10:08:21 -0400631static bool try_replace_expression(BasicBlock* b,
632 std::vector<BasicBlock::Node>::iterator* iter,
633 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400634 std::unique_ptr<Expression>* target = (*iter)->expression();
635 if (!b->tryRemoveExpression(iter)) {
636 *target = std::move(*newExpression);
637 return false;
638 }
639 *target = std::move(*newExpression);
640 return b->tryInsertExpression(iter, target);
641}
642
643/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400644 * Returns true if the expression is a constant numeric literal with the specified value, or a
645 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400646 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400647template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400648static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400649 switch (expr.kind()) {
650 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400651 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400652
Ethan Nicholase6592142020-09-08 10:22:09 -0400653 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400654 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400655
Ethan Nicholase6592142020-09-08 10:22:09 -0400656 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400657 const Constructor& constructor = expr.as<Constructor>();
658 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400659 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400660 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400661 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500662 if (constructor.componentType().isFloat()) {
663 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400664 if (constructor.getFVecComponent(i) != value) {
665 return false;
666 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500667 }
668 return true;
669 } else if (constructor.componentType().isInteger()) {
670 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400671 if (constructor.getIVecComponent(i) != value) {
672 return false;
673 }
674 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500675 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400676 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500677 // Other types (e.g. boolean) might occur, but aren't supported here.
678 return false;
John Stiles9d944232020-08-19 09:56:49 -0400679
Ethan Nicholase6592142020-09-08 10:22:09 -0400680 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400681 SkASSERT(constructor.arguments().size() == 1);
682 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400683
684 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400685 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400686 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400687 }
688 return false;
689 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400690 default:
691 return false;
692 }
693}
694
695/**
696 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
697 * and CFG structures).
698 */
John Stilesafbf8992020-08-18 10:08:21 -0400699static void delete_left(BasicBlock* b,
700 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400701 Compiler::OptimizationContext* optimizationContext) {
702 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400703 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400704 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400705 Expression& left = *bin.left();
706 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400707 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400708 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400709 if (bin.getOperator() == Token::Kind::TK_EQ) {
710 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400711 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400712 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400713 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400714 // Remove references within LHS.
715 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400716 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400717 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400718 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400719 return;
720 }
721 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400722 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400723 return;
724 }
725 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400726 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400727 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400728 return;
729 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400730 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400731 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400732}
733
734/**
735 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
736 * CFG structures).
737 */
John Stilesafbf8992020-08-18 10:08:21 -0400738static void delete_right(BasicBlock* b,
739 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400740 Compiler::OptimizationContext* optimizationContext) {
741 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400742 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400743 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400744 std::unique_ptr<Expression>& leftPointer = bin.left();
745 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400746 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400747 // Remove references within RHS.
748 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400749 if (!b->tryRemoveExpressionBefore(iter, &right)) {
750 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400751 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400752 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400753 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400754 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400755 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400756 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400757 return;
758 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400759 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400760 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400761 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400762 return;
763 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400764 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400765 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400766}
767
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400768/**
769 * Constructs the specified type using a single argument.
770 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400771static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400772 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400773 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400774 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400775 return result;
776}
777
778/**
779 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
780 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
781 */
782static void vectorize(BasicBlock* b,
783 std::vector<BasicBlock::Node>::iterator* iter,
784 const Type& type,
785 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400786 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400787 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500788 SkASSERT(type.isVector());
789 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400790 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400791 std::unique_ptr<Expression>* target = (*iter)->expression();
792 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400793 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400794 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400795 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400796 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400797 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400798 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400799 }
800 }
801}
802
803/**
804 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
805 * left to yield vec<n>(x).
806 */
807static void vectorize_left(BasicBlock* b,
808 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400809 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400810 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400811 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400812 optimizationContext->fUsage->remove(bin.right().get());
813 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400814}
815
816/**
817 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
818 * right to yield vec<n>(y).
819 */
820static void vectorize_right(BasicBlock* b,
821 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400822 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400823 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400824 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400825 optimizationContext->fUsage->remove(bin.left().get());
826 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400827}
828
829// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400830static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400831 switch (expr.kind()) {
832 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400833 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400834 break;
835 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400836 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400837 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400838 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400839 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400840 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400841 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400842 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400843 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400844 break;
845 default:
846 ABORT("shouldn't be writing to this kind of expression\n");
847 break;
848 }
849}
850
Ethan Nicholascb670962017-04-20 19:31:52 -0400851void Compiler::simplifyExpression(DefinitionMap& definitions,
852 BasicBlock& b,
853 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400854 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400855 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400856 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500857
Ethan Nicholascb670962017-04-20 19:31:52 -0400858 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400859 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
860 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400861 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400862 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400863 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400864 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400865 // Remove references within 'expr', add references within 'optimized'
866 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400867 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400868 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400869 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400870 }
John Stiles70025e52020-09-28 16:08:58 -0400871 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400872 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400873 }
874 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400875 switch (expr->kind()) {
876 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400877 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400878 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400879 if (ref.refKind() != VariableReference::RefKind::kWrite &&
880 ref.refKind() != VariableReference::RefKind::kPointer &&
881 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400882 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
883 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000884 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400885 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400886 }
887 break;
888 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400889 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400890 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400891 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400892 // ternary has a constant test, replace it with either the true or
893 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400894 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400895 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400896 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400897 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400898 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400899 optimizationContext->fUpdated = true;
900 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400901 }
902 break;
903 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400904 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400905 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400906 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400907 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400908 break;
909 }
John Stiles2d4f9592020-10-30 10:29:12 -0400910 Expression& left = *bin->left();
911 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400912 const Type& leftType = left.type();
913 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400914 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500915 if ((!leftType.isScalar() && !leftType.isVector()) ||
916 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400917 break;
918 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400919 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400920 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400921 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500922 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400923 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400924 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400925 } else {
926 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400927 // 1 * float4(x) -> float4(x)
928 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400929 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400930 }
931 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400932 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500933 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400934 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400935 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400936 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400937 } else {
938 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400939 // float4(0) * x -> float4(0)
940 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400941 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400942 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500943 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400944 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400945 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400946 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500947 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400948 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400949 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400950 } else {
951 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400952 // float4(x) * 1 -> float4(x)
953 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400954 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400955 }
956 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400957 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500958 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400959 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400960 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400961 } else {
962 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400963 // x * float4(0) -> float4(0)
964 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400965 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400966 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500967 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400968 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400969 }
970 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400971 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400972 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500973 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400974 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400975 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400976 } else {
977 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400978 // 0 + float4(x) -> float4(x)
979 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400980 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400981 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400982 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500983 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400984 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400985 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400986 } else {
987 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400988 // float4(x) + 0 -> float4(x)
989 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400990 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400991 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400992 }
993 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400994 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400995 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500996 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400997 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400998 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400999 } else {
1000 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001001 // float4(x) - 0 -> float4(x)
1002 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001003 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001004 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001005 }
1006 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001007 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001008 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -05001009 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001010 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001011 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001012 } else {
1013 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001014 // float4(x) / 1 -> float4(x)
1015 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001016 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001017 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001018 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -05001019 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001020 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001021 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001022 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001023 } else {
1024 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001025 // float4(0) / x -> float4(0)
1026 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001027 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001028 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001029 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001030 }
1031 }
1032 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001033 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001034 if (is_constant(right, 0)) {
1035 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001036 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001037 }
1038 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001039 case Token::Kind::TK_MINUSEQ:
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_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001046 if (is_constant(right, 1)) {
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_SLASHEQ:
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 Nicholascb670962017-04-20 19:31:52 -04001055 }
1056 break;
1057 default:
1058 break;
1059 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001060 break;
1061 }
John Stilesf5c1d042020-11-21 23:26:07 -05001062 case Expression::Kind::kConstructor: {
1063 // Find constructors embedded inside constructors and flatten them out where possible.
1064 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
1065 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
1066 // Leave single-argument constructors alone, though. These might be casts or splats.
1067 Constructor& c = expr->as<Constructor>();
1068 if (c.type().columns() > 1) {
1069 // Inspect each constructor argument to see if it's a candidate for flattening.
1070 // Remember matched arguments in a bitfield, "argsToOptimize".
1071 int argsToOptimize = 0;
1072 int currBit = 1;
1073 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1074 if (arg->is<Constructor>()) {
1075 Constructor& inner = arg->as<Constructor>();
1076 if (inner.arguments().size() > 1 &&
1077 inner.type().componentType() == c.type().componentType()) {
1078 argsToOptimize |= currBit;
1079 }
1080 }
1081 currBit <<= 1;
1082 }
1083 if (argsToOptimize) {
1084 // We found at least one argument that could be flattened out. Re-walk the
1085 // constructor args and flatten the candidates we found during our initial pass.
1086 ExpressionArray flattened;
1087 flattened.reserve_back(c.type().columns());
1088 currBit = 1;
1089 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1090 if (argsToOptimize & currBit) {
1091 Constructor& inner = arg->as<Constructor>();
1092 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
1093 flattened.push_back(innerArg->clone());
1094 }
1095 } else {
1096 flattened.push_back(arg->clone());
1097 }
1098 currBit <<= 1;
1099 }
1100 auto optimized = std::unique_ptr<Expression>(
1101 new Constructor(c.fOffset, &c.type(), std::move(flattened)));
1102 // No fUsage change; no references have been added or removed anywhere.
1103 optimizationContext->fUpdated = true;
1104 if (!try_replace_expression(&b, iter, &optimized)) {
1105 optimizationContext->fNeedsRescan = true;
1106 return;
1107 }
1108 SkASSERT((*iter)->isExpression());
1109 break;
1110 }
1111 }
1112 break;
1113 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001114 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001115 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -05001116 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001117 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001118 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001119 for (int i = 0; i < (int) s.components().size(); ++i) {
1120 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001121 identity = false;
1122 break;
1123 }
1124 }
1125 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001126 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001127 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001128 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001129 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001130 return;
1131 }
John Stiles70025e52020-09-28 16:08:58 -04001132 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001133 break;
1134 }
1135 }
John Stiles108bbe22020-11-18 11:10:38 -05001136 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1137 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001138 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001139 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001140 for (int c : s.components()) {
1141 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001142 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001143 optimizationContext->fUpdated = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001144 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001145 final));
John Stiles108bbe22020-11-18 11:10:38 -05001146 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001147 if (!try_replace_expression(&b, iter, &replacement)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001148 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001149 return;
1150 }
John Stiles70025e52020-09-28 16:08:58 -04001151 SkASSERT((*iter)->isExpression());
John Stiles108bbe22020-11-18 11:10:38 -05001152 break;
1153 }
1154 // Optimize swizzles of constructors.
1155 if (s.base()->is<Constructor>()) {
1156 Constructor& base = s.base()->as<Constructor>();
1157 std::unique_ptr<Expression> replacement;
1158 const Type& componentType = base.type().componentType();
1159 int swizzleSize = s.components().size();
1160
1161 // The IR generator has already converted any zero/one swizzle components into
1162 // constructors containing zero/one args. Confirm that this is true by checking that
1163 // our swizzle components are all `xyzw` (values 0 through 3).
1164 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1165 [](int8_t c) { return c >= 0 && c <= 3; }));
1166
John Stiles9aeed132020-11-24 17:36:06 -05001167 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001168 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1169 // components don't actually matter since all fields are the same.
1170 ExpressionArray newArgs;
1171 newArgs.push_back(base.arguments().front()->clone());
1172 replacement = std::make_unique<Constructor>(
1173 base.fOffset,
1174 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1175 std::move(newArgs));
1176
John Stilesa60ac0c2020-12-22 08:59:51 -05001177 // We're replacing an expression with a cloned version; we'll need a rescan.
1178 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1179 // reference counts.
1180 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001181 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001182 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001183 break;
1184 }
1185
John Stiles0777ac42020-11-19 11:06:47 -05001186 // Swizzles can duplicate some elements and discard others, e.g.
1187 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1188 // - Expressions with side effects need to occur exactly once, even if they
1189 // would otherwise be swizzle-eliminated
1190 // - Non-trivial expressions should not be repeated, but elimination is OK.
1191 //
1192 // Look up the argument for the constructor at each index. This is typically simple
1193 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1194 // seems. This example would result in:
1195 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1196 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1197 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1198 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1199 struct ConstructorArgMap {
1200 int8_t fArgIndex;
1201 int8_t fComponent;
1202 };
1203
1204 int numConstructorArgs = base.type().columns();
1205 ConstructorArgMap argMap[4] = {};
1206 int writeIdx = 0;
1207 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1208 const Expression& expr = *base.arguments()[argIdx];
1209 int argWidth = expr.type().columns();
1210 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1211 argMap[writeIdx].fArgIndex = argIdx;
1212 argMap[writeIdx].fComponent = componentIdx;
1213 ++writeIdx;
1214 }
1215 }
1216 SkASSERT(writeIdx == numConstructorArgs);
1217
1218 // Count up the number of times each constructor argument is used by the
1219 // swizzle.
1220 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1221 // - bar.yz is referenced 3 times, by `.x_xy`
1222 // - half(foo) is referenced 1 time, by `._w__`
1223 int8_t exprUsed[4] = {};
1224 for (int c : s.components()) {
1225 exprUsed[argMap[c].fArgIndex]++;
1226 }
1227
1228 bool safeToOptimize = true;
1229 for (int index = 0; index < numConstructorArgs; ++index) {
1230 int8_t constructorArgIndex = argMap[index].fArgIndex;
1231 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1232
1233 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001234 if (exprUsed[constructorArgIndex] > 1 &&
1235 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001236 safeToOptimize = false;
1237 break;
1238 }
1239 // Check that side-effect-bearing expressions are swizzled in exactly once.
1240 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1241 safeToOptimize = false;
1242 break;
1243 }
1244 }
1245
1246 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001247 struct ReorderedArgument {
1248 int8_t fArgIndex;
1249 ComponentArray fComponents;
1250 };
1251 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001252 for (int c : s.components()) {
1253 const ConstructorArgMap& argument = argMap[c];
1254 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1255
John Stiles9aeed132020-11-24 17:36:06 -05001256 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001257 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001258 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001259 reorderedArgs.push_back({argument.fArgIndex,
1260 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001261 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001262 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001263 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001264 if (reorderedArgs.empty() ||
1265 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1266 // This can't be combined with the previous argument. Add a new one.
1267 reorderedArgs.push_back({argument.fArgIndex,
1268 ComponentArray{argument.fComponent}});
1269 } else {
1270 // Since we know this argument uses components, it should already
1271 // have at least one component set.
1272 SkASSERT(!reorderedArgs.back().fComponents.empty());
1273 // Build up the current argument with one more component.
1274 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1275 }
John Stiles0777ac42020-11-19 11:06:47 -05001276 }
1277 }
John Stilesd9076cb2020-11-19 12:18:36 -05001278
1279 // Convert our reordered argument list to an actual array of expressions, with
1280 // the new order and any new inner swizzles that need to be applied. Note that
1281 // we expect followup passes to clean up the inner swizzles.
1282 ExpressionArray newArgs;
1283 newArgs.reserve_back(swizzleSize);
1284 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1285 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1286 if (reorderedArg.fComponents.empty()) {
1287 newArgs.push_back(baseArg.clone());
1288 } else {
1289 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1290 reorderedArg.fComponents));
1291 }
1292 }
1293
1294 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001295 replacement = std::make_unique<Constructor>(
1296 base.fOffset,
1297 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1298 std::move(newArgs));
1299
John Stilesa60ac0c2020-12-22 08:59:51 -05001300 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001301 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001302
1303 // We're replacing an expression with a cloned version; we'll need a rescan.
1304 try_replace_expression(&b, iter, &replacement);
1305 optimizationContext->fUpdated = true;
1306 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001307 }
John Stiles108bbe22020-11-18 11:10:38 -05001308 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001309 }
John Stiles30212b72020-06-11 17:55:07 -04001310 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001311 }
1312 default:
1313 break;
1314 }
1315}
1316
John Stiles92219b42020-06-15 12:32:24 -04001317// Returns true if this statement could potentially execute a break at the current level. We ignore
1318// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001319static bool contains_conditional_break(Statement& stmt) {
1320 class ContainsConditionalBreak : public ProgramVisitor {
1321 public:
1322 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001323 switch (stmt.kind()) {
1324 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001325 return this->INHERITED::visitStatement(stmt);
1326
Ethan Nicholase6592142020-09-08 10:22:09 -04001327 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001328 return fInConditional > 0;
1329
Ethan Nicholase6592142020-09-08 10:22:09 -04001330 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001331 ++fInConditional;
1332 bool result = this->INHERITED::visitStatement(stmt);
1333 --fInConditional;
1334 return result;
1335 }
1336
1337 default:
1338 return false;
1339 }
1340 }
1341
1342 int fInConditional = 0;
1343 using INHERITED = ProgramVisitor;
1344 };
1345
1346 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001347}
1348
Ethan Nicholas5005a222018-08-24 13:06:27 -04001349// returns true if this statement definitely executes a break at the current level (we ignore
1350// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001351static bool contains_unconditional_break(Statement& stmt) {
1352 class ContainsUnconditionalBreak : public ProgramVisitor {
1353 public:
1354 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001355 switch (stmt.kind()) {
1356 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001357 return this->INHERITED::visitStatement(stmt);
1358
Ethan Nicholase6592142020-09-08 10:22:09 -04001359 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001360 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001361
1362 default:
1363 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001364 }
John Stilesb92641c2020-08-31 18:09:01 -04001365 }
John Stiles92219b42020-06-15 12:32:24 -04001366
John Stilesb92641c2020-08-31 18:09:01 -04001367 using INHERITED = ProgramVisitor;
1368 };
John Stiles92219b42020-06-15 12:32:24 -04001369
John Stilesb92641c2020-08-31 18:09:01 -04001370 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001371}
1372
John Stiles8f2a0cf2020-10-13 12:48:21 -04001373static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001374 switch (stmt->kind()) {
1375 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001376 // Recurse into the block.
1377 Block& block = static_cast<Block&>(*stmt);
1378
John Stiles8f2a0cf2020-10-13 12:48:21 -04001379 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001380 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001381 for (std::unique_ptr<Statement>& stmt : block.children()) {
1382 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001383 }
John Stiles92219b42020-06-15 12:32:24 -04001384
1385 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001386 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001387 break;
John Stiles92219b42020-06-15 12:32:24 -04001388 }
1389
Ethan Nicholase6592142020-09-08 10:22:09 -04001390 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001391 // Do not append a break to the target.
1392 break;
1393
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001394 default:
John Stiles92219b42020-06-15 12:32:24 -04001395 // Append normal statements to the target.
1396 target->push_back(std::move(stmt));
1397 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001398 }
1399}
1400
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001401// Returns a block containing all of the statements that will be run if the given case matches
1402// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1403// broken by this call and must then be discarded).
1404// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1405// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001406static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1407 SwitchCase* caseToCapture) {
1408 // We have to be careful to not move any of the pointers until after we're sure we're going to
1409 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1410 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001411 auto iter = switchStatement->cases().begin();
1412 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001413 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001414 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001415 }
John Stiles92219b42020-06-15 12:32:24 -04001416 }
1417
1418 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1419 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1420 // statements that we can use for simplification.
1421 auto startIter = iter;
1422 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001423 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001424 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001425 if (contains_conditional_break(*stmt)) {
1426 // We can't reduce switch-cases to a block when they have conditional breaks.
1427 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001428 }
John Stiles92219b42020-06-15 12:32:24 -04001429
1430 if (contains_unconditional_break(*stmt)) {
1431 // We found an unconditional break. We can use this block, but we need to strip
1432 // out the break statement.
1433 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001434 break;
1435 }
1436 }
John Stiles92219b42020-06-15 12:32:24 -04001437
1438 if (unconditionalBreakStmt != nullptr) {
1439 break;
1440 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001441 }
John Stiles92219b42020-06-15 12:32:24 -04001442
1443 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1444 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001445 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001446
1447 // We can move over most of the statements as-is.
1448 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001449 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001450 caseStmts.push_back(std::move(stmt));
1451 }
1452 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001453 }
John Stiles92219b42020-06-15 12:32:24 -04001454
1455 // If we found an unconditional break at the end, we need to move what we can while avoiding
1456 // that break.
1457 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001458 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001459 if (stmt.get() == unconditionalBreakStmt) {
1460 move_all_but_break(stmt, &caseStmts);
1461 unconditionalBreakStmt = nullptr;
1462 break;
1463 }
1464
1465 caseStmts.push_back(std::move(stmt));
1466 }
1467 }
1468
1469 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1470
1471 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001472 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001473}
1474
Ethan Nicholascb670962017-04-20 19:31:52 -04001475void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001476 BasicBlock& b,
1477 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001478 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001479 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001480 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001481 switch (stmt->kind()) {
1482 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001483 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001484 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001485 (!varDecl.value() ||
1486 !varDecl.value()->hasSideEffects())) {
1487 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001488 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001489 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001490 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001491 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001492 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001493 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001494 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001495 }
1496 break;
1497 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001498 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001499 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001500 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001501 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001502 if (i.test()->as<BoolLiteral>().value()) {
1503 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001504 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001505 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001506 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001507 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001508 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001509 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001510 }
1511 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001512 optimizationContext->fUpdated = true;
1513 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001514 break;
1515 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001516 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001517 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001518 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001519 optimizationContext->fUpdated = true;
1520 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001521 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001522 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001523 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001524 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001525 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001526 (*iter)->setStatement(
1527 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001528 } else {
1529 // no if, no else, no test side effects, kill the whole if
1530 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001531 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001532 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001533 optimizationContext->fUpdated = true;
1534 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001535 }
1536 break;
1537 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001538 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001539 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001540 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001541 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001542 // switch is constant, replace it with the case that matches
1543 bool found = false;
1544 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001545 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1546 if (!c->value()) {
1547 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001548 continue;
1549 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001550 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001551 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001552 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001553 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001554 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001555 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001556 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001557 break;
1558 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001559 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1560 optimizationContext->fSilences.find(&s) ==
1561 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001562 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001563 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001564 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001565 }
1566 return; // can't simplify
1567 }
1568 }
1569 }
1570 if (!found) {
1571 // no matching case. use default if it exists, or kill the whole thing
1572 if (defaultCase) {
1573 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1574 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001575 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001576 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001577 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1578 optimizationContext->fSilences.find(&s) ==
1579 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001580 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001581 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001582 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001583 }
1584 return; // can't simplify
1585 }
1586 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001587 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001588 }
1589 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001590 optimizationContext->fUpdated = true;
1591 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001592 }
1593 break;
1594 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001595 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001596 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001597 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001598 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001599 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001600 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001601 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001602 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001603 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001604 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001605 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001606 }
1607 break;
1608 }
1609 default:
1610 break;
1611 }
1612}
1613
Brian Osman010ce6a2020-10-19 16:34:10 -04001614bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001615 bool madeChanges = false;
1616
Ethan Nicholascb670962017-04-20 19:31:52 -04001617 CFG cfg = CFGGenerator().getCFG(f);
1618 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001619
1620 // check for unreachable code
1621 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001622 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001623 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001624 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001625 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001626 if (node.isStatement()) {
1627 offset = (*node.statement())->fOffset;
1628 } else {
1629 offset = (*node.expression())->fOffset;
1630 if ((*node.expression())->is<BoolLiteral>()) {
1631 // Function inlining can generate do { ... } while(false) loops which always
1632 // break, so the boolean condition is considered unreachable. Since not being
1633 // able to reach a literal is a non-issue in the first place, we don't report an
1634 // error in this case.
1635 continue;
1636 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001637 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001638 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001639 }
1640 }
1641 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001642 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001643 }
1644
Ethan Nicholascb670962017-04-20 19:31:52 -04001645 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001646 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001647 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001648 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001649 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001650 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001651 cfg = CFGGenerator().getCFG(f);
1652 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001653 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001654 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001655
John Stiles7d3f0892020-11-03 11:35:01 -05001656 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001657 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001658
1659 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1660 if (eliminatedBlockIds.test(blockId)) {
1661 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1662 optimizationContext.fUpdated = true;
1663 optimizationContext.fNeedsRescan = true;
1664 break;
1665 }
1666
1667 BasicBlock& b = cfg.fBlocks[blockId];
1668 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001669 // Block was reachable before optimization, but has since become unreachable. In
1670 // addition to being dead code, it's broken - since control flow can't reach it, no
1671 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001672 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001673 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001674 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001675 // Eliminating a node runs the risk of eliminating that node's exits as
1676 // well. Keep track of this and do a rescan if we are about to access one
1677 // of these.
1678 for (BlockId id : b.fExits) {
1679 eliminatedBlockIds.set(id);
1680 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001681 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001682 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001683 }
1684 }
1685 continue;
1686 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001687 DefinitionMap definitions = b.fBefore;
1688
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001689 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1690 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001691 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001692 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001693 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001694 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001695 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001696 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001697 break;
1698 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001699 this->addDefinitions(*iter, &definitions);
1700 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001701
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001702 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001703 break;
1704 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001705 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001706 madeChanges |= optimizationContext.fUpdated;
1707 } while (optimizationContext.fUpdated);
1708 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001709
Ethan Nicholas91a10532017-06-22 11:24:38 -04001710 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001711 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001712 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1713 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001714 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001715 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001716 switch (s.kind()) {
1717 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001718 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001719 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001720 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001721 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001722 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001723 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001724 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001725 if (s.as<SwitchStatement>().isStatic() &&
1726 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1727 optimizationContext.fSilences.find(&s) ==
1728 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001729 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001730 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001731 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001732 break;
1733 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001734 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001735 break;
1736 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001737 } else {
1738 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001739 }
1740 }
1741 }
1742
ethannicholas22f939e2016-10-13 13:25:34 -07001743 // check for missing return
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001744 if (f.declaration().returnType() != *fContext->fVoid_Type) {
John Stiles61e75e32020-10-01 15:42:37 -04001745 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001746 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001747 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001748 }
1749 }
John Stiles0cc193a2020-09-09 09:39:34 -04001750
1751 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001752}
1753
Brian Osman32d53552020-09-23 13:55:20 -04001754std::unique_ptr<Program> Compiler::convertProgram(
1755 Program::Kind kind,
1756 String text,
1757 const Program::Settings& settings,
1758 const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
1759 SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001760
Brian Osman0006ad02020-11-18 15:38:39 -05001761 // Loading and optimizing our base module might reset the inliner, so do that first,
1762 // *then* configure the inliner with the settings for this program.
1763 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1764
ethannicholasb3058bd2016-07-01 08:22:01 -07001765 fErrorText = "";
1766 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001767 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001768
1769 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001770 std::unique_ptr<String> textPtr(new String(std::move(text)));
1771 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001772
John Stiles5c7bb322020-10-22 11:09:15 -04001773 // Enable node pooling while converting and optimizing the program for a performance boost.
1774 // The Program will take ownership of the pool.
John Stiles2d68ea32020-10-22 15:42:27 -04001775 std::unique_ptr<Pool> pool = Pool::Create();
1776 pool->attachToThread();
Brian Osman0006ad02020-11-18 15:38:39 -05001777 IRGenerator::IRBundle ir =
1778 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
1779 textPtr->c_str(), textPtr->size(), externalValues);
John Stiles5c7bb322020-10-22 11:09:15 -04001780 auto program = std::make_unique<Program>(kind,
1781 std::move(textPtr),
1782 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001783 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001784 fContext,
1785 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001786 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001787 std::move(ir.fModifiers),
1788 std::move(ir.fSymbolTable),
1789 std::move(pool),
1790 ir.fInputs);
1791 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001792 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001793 // Do not return programs that failed to compile.
1794 } else if (settings.fOptimize && !this->optimize(*program)) {
1795 // Do not return programs that failed to optimize.
1796 } else {
1797 // We have a successful program!
1798 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001799 }
John Stiles5c7bb322020-10-22 11:09:15 -04001800
1801 program->fPool->detachFromThread();
1802 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001803}
1804
Brian Osman0006ad02020-11-18 15:38:39 -05001805bool Compiler::optimize(LoadedModule& module) {
1806 SkASSERT(!fErrorCount);
1807 Program::Settings settings;
1808 fIRGenerator->fKind = module.fKind;
1809 fIRGenerator->fSettings = &settings;
1810 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1811
1812 fInliner.reset(fModifiers.back().get(), &settings);
1813
1814 while (fErrorCount == 0) {
1815 bool madeChanges = false;
1816
1817 // Scan and optimize based on the control-flow graph for each function.
1818 for (const auto& element : module.fElements) {
1819 if (element->is<FunctionDefinition>()) {
1820 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1821 }
1822 }
1823
1824 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001825 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001826
1827 if (!madeChanges) {
1828 break;
1829 }
1830 }
1831 return fErrorCount == 0;
1832}
1833
Ethan Nicholas00543112018-07-31 09:44:36 -04001834bool Compiler::optimize(Program& program) {
1835 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001836 fIRGenerator->fKind = program.fKind;
1837 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001838 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001839
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001840 while (fErrorCount == 0) {
1841 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001842
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001843 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001844 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001845 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001846 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001847 }
1848 }
1849
1850 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001851 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001852
1853 // Remove dead functions. We wait until after analysis so that we still report errors,
1854 // even in unused code.
1855 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001856 auto isDeadFunction = [&](const ProgramElement* element) {
1857 if (!element->is<FunctionDefinition>()) {
1858 return false;
1859 }
1860 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1861 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1862 usage->remove(*element);
1863 madeChanges = true;
1864 return true;
1865 }
1866 return false;
1867 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001868 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001869 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001870 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001871 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001872 }),
1873 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001874 program.fSharedElements.erase(
1875 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1876 isDeadFunction),
1877 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001878 }
1879
1880 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001881 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001882 auto isDeadVariable = [&](const ProgramElement* element) {
1883 if (!element->is<GlobalVarDeclaration>()) {
1884 return false;
1885 }
1886 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1887 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1888 if (usage->isDead(varDecl.var())) {
1889 madeChanges = true;
1890 return true;
1891 }
1892 return false;
1893 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001894 program.fElements.erase(
1895 std::remove_if(program.fElements.begin(), program.fElements.end(),
1896 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001897 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001898 }),
1899 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001900 program.fSharedElements.erase(
1901 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1902 isDeadVariable),
1903 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001904 }
John Stiles73a6bff2020-09-09 13:40:37 -04001905
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001906 if (!madeChanges) {
1907 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001908 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001909 }
1910 return fErrorCount == 0;
1911}
1912
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001913#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1914
Ethan Nicholas00543112018-07-31 09:44:36 -04001915bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001916#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001917 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001918 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001919 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001920 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001921 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001922 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001923 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001924 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001925 String errors;
1926 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1927 const char* m) {
1928 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001929 };
1930 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001931
1932 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1933 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1934 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1935 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1936
1937 if (!result) {
1938#if defined(SKSL_STANDALONE)
1939 // Convert the string-stream to a SPIR-V disassembly.
1940 std::string disassembly;
1941 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1942 errors.append(disassembly);
1943 }
1944 this->error(-1, errors);
1945#else
1946 SkDEBUGFAILF("%s", errors.c_str());
1947#endif
1948 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001949 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001950 }
1951#else
Brian Osman88cda172020-10-09 12:05:16 -04001952 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001953 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001954 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001955#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001956 return result;
1957}
1958
Ethan Nicholas00543112018-07-31 09:44:36 -04001959bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001960 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001961 bool result = this->toSPIRV(program, buffer);
1962 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001963 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001964 }
1965 return result;
1966}
1967
Ethan Nicholas00543112018-07-31 09:44:36 -04001968bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001969 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001970 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001971 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001972 return result;
1973}
1974
Ethan Nicholas00543112018-07-31 09:44:36 -04001975bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001976 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001977 bool result = this->toGLSL(program, buffer);
1978 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001979 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001980 }
1981 return result;
1982}
1983
Brian Osmanc0243912020-02-19 15:35:26 -05001984bool Compiler::toHLSL(Program& program, String* out) {
1985 String spirv;
1986 if (!this->toSPIRV(program, &spirv)) {
1987 return false;
1988 }
1989
1990 return SPIRVtoHLSL(spirv, out);
1991}
1992
Ethan Nicholas00543112018-07-31 09:44:36 -04001993bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001994 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001995 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001996 return result;
1997}
1998
Ethan Nicholas00543112018-07-31 09:44:36 -04001999bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04002000 StringStream buffer;
2001 bool result = this->toMetal(program, buffer);
2002 if (result) {
2003 *out = buffer.str();
2004 }
2005 return result;
2006}
2007
Greg Daniela28ea672020-09-25 11:12:56 -04002008#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002009bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002010 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002011 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002012 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04002013 return result;
2014}
2015
Ethan Nicholas00543112018-07-31 09:44:36 -04002016bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04002017 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04002018 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04002019 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002020 return result;
2021}
Greg Daniela28ea672020-09-25 11:12:56 -04002022#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04002023
Ethan Nicholas2a479a52020-08-18 16:29:45 -04002024#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04002025
2026#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04002027bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04002028 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04002029 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05002030 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04002031 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04002032 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05002033 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04002034 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04002035 return result;
2036}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04002037#endif
2038
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002039std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Brian Osman88cda172020-10-09 12:05:16 -04002040 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002041 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04002042 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
2043 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04002044 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002045 return result;
2046 }
2047 return nullptr;
2048}
2049
Brian Osman401a0092020-09-10 14:47:24 -04002050const char* Compiler::OperatorName(Token::Kind op) {
2051 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002052 case Token::Kind::TK_PLUS: return "+";
2053 case Token::Kind::TK_MINUS: return "-";
2054 case Token::Kind::TK_STAR: return "*";
2055 case Token::Kind::TK_SLASH: return "/";
2056 case Token::Kind::TK_PERCENT: return "%";
2057 case Token::Kind::TK_SHL: return "<<";
2058 case Token::Kind::TK_SHR: return ">>";
2059 case Token::Kind::TK_LOGICALNOT: return "!";
2060 case Token::Kind::TK_LOGICALAND: return "&&";
2061 case Token::Kind::TK_LOGICALOR: return "||";
2062 case Token::Kind::TK_LOGICALXOR: return "^^";
2063 case Token::Kind::TK_BITWISENOT: return "~";
2064 case Token::Kind::TK_BITWISEAND: return "&";
2065 case Token::Kind::TK_BITWISEOR: return "|";
2066 case Token::Kind::TK_BITWISEXOR: return "^";
2067 case Token::Kind::TK_EQ: return "=";
2068 case Token::Kind::TK_EQEQ: return "==";
2069 case Token::Kind::TK_NEQ: return "!=";
2070 case Token::Kind::TK_LT: return "<";
2071 case Token::Kind::TK_GT: return ">";
2072 case Token::Kind::TK_LTEQ: return "<=";
2073 case Token::Kind::TK_GTEQ: return ">=";
2074 case Token::Kind::TK_PLUSEQ: return "+=";
2075 case Token::Kind::TK_MINUSEQ: return "-=";
2076 case Token::Kind::TK_STAREQ: return "*=";
2077 case Token::Kind::TK_SLASHEQ: return "/=";
2078 case Token::Kind::TK_PERCENTEQ: return "%=";
2079 case Token::Kind::TK_SHLEQ: return "<<=";
2080 case Token::Kind::TK_SHREQ: return ">>=";
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002081 case Token::Kind::TK_BITWISEANDEQ: return "&=";
2082 case Token::Kind::TK_BITWISEOREQ: return "|=";
2083 case Token::Kind::TK_BITWISEXOREQ: return "^=";
2084 case Token::Kind::TK_PLUSPLUS: return "++";
2085 case Token::Kind::TK_MINUSMINUS: return "--";
2086 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002087 default:
Brian Osman401a0092020-09-10 14:47:24 -04002088 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002089 }
2090}
2091
2092
2093bool Compiler::IsAssignment(Token::Kind op) {
2094 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002095 case Token::Kind::TK_EQ: // fall through
2096 case Token::Kind::TK_PLUSEQ: // fall through
2097 case Token::Kind::TK_MINUSEQ: // fall through
2098 case Token::Kind::TK_STAREQ: // fall through
2099 case Token::Kind::TK_SLASHEQ: // fall through
2100 case Token::Kind::TK_PERCENTEQ: // fall through
2101 case Token::Kind::TK_SHLEQ: // fall through
2102 case Token::Kind::TK_SHREQ: // fall through
2103 case Token::Kind::TK_BITWISEOREQ: // fall through
2104 case Token::Kind::TK_BITWISEXOREQ: // fall through
John Stiles8b3b1592020-11-23 11:06:44 -05002105 case Token::Kind::TK_BITWISEANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002106 return true;
2107 default:
2108 return false;
2109 }
2110}
2111
Brian Osman401a0092020-09-10 14:47:24 -04002112Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
2113 switch (op) {
2114 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
2115 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
2116 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
2117 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
2118 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
2119 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
2120 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
2121 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
2122 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
2123 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
Brian Osman401a0092020-09-10 14:47:24 -04002124 default: return op;
2125 }
2126}
2127
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002128Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05002129 if (fSource && offset >= 0) {
2130 int line = 1;
2131 int column = 1;
2132 for (int i = 0; i < offset; i++) {
2133 if ((*fSource)[i] == '\n') {
2134 ++line;
2135 column = 1;
2136 }
2137 else {
2138 ++column;
2139 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002140 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05002141 return Position(line, column);
2142 } else {
2143 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002144 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002145}
2146
2147void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002148 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002149 Position pos = this->position(offset);
Ethan Nicholas3c729892020-12-07 12:47:17 -05002150 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07002151}
2152
Ethan Nicholasdcd2f862020-12-17 23:24:25 +00002153String Compiler::errorText() {
2154 this->writeErrorCount();
Ethan Nicholas00543112018-07-31 09:44:36 -04002155 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002156 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07002157 return result;
2158}
2159
2160void Compiler::writeErrorCount() {
2161 if (fErrorCount) {
2162 fErrorText += to_string(fErrorCount) + " error";
2163 if (fErrorCount > 1) {
2164 fErrorText += "s";
2165 }
2166 fErrorText += "\n";
2167 }
2168}
2169
John Stilesa6841be2020-08-06 14:11:56 -04002170} // namespace SkSL