blob: bcc0eba8502b044a3bd9d597964631eebe8da7a9 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stilesb92641c2020-08-31 18:09:01 -040013#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/sksl/SkSLCFGGenerator.h"
15#include "src/sksl/SkSLCPPCodeGenerator.h"
16#include "src/sksl/SkSLGLSLCodeGenerator.h"
17#include "src/sksl/SkSLHCodeGenerator.h"
18#include "src/sksl/SkSLIRGenerator.h"
19#include "src/sksl/SkSLMetalCodeGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050020#include "src/sksl/SkSLOperators.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040021#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050023#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/sksl/ir/SkSLEnum.h"
25#include "src/sksl/ir/SkSLExpression.h"
26#include "src/sksl/ir/SkSLExpressionStatement.h"
27#include "src/sksl/ir/SkSLFunctionCall.h"
28#include "src/sksl/ir/SkSLIntLiteral.h"
29#include "src/sksl/ir/SkSLModifiersDeclaration.h"
30#include "src/sksl/ir/SkSLNop.h"
31#include "src/sksl/ir/SkSLSymbolTable.h"
32#include "src/sksl/ir/SkSLTernaryExpression.h"
33#include "src/sksl/ir/SkSLUnresolvedFunction.h"
34#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040035#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070036
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040037#include <fstream>
38
Ethan Nicholasa11035b2019-11-26 16:27:47 -050039#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
40#include "include/gpu/GrContextOptions.h"
41#include "src/gpu/GrShaderCaps.h"
42#endif
43
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040044#ifdef SK_ENABLE_SPIRV_VALIDATION
45#include "spirv-tools/libspirv.hpp"
46#endif
47
Brian Osman3d87e9f2020-10-08 11:50:22 -040048#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040049
Brian Osman3d87e9f2020-10-08 11:50:22 -040050// In standalone mode, we load the textual sksl source files. GN generates or copies these files
51// to the skslc executable directory. The "data" in this mode is just the filename.
52#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
53
54#else
55
56// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040057#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
58#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
59#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
60#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050061#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050062#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040063#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
64
Brian Osman3d87e9f2020-10-08 11:50:22 -040065#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
66 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040067
68#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040069
ethannicholasb3058bd2016-07-01 08:22:01 -070070namespace SkSL {
71
Brian Osman88cda172020-10-09 12:05:16 -040072class AutoSource {
73public:
74 AutoSource(Compiler* compiler, const String* source)
75 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
76 fCompiler->fSource = source;
77 }
78
79 ~AutoSource() { fCompiler->fSource = fOldSource; }
80
81 Compiler* fCompiler;
82 const String* fOldSource;
83};
84
Brian Osmand7e76592020-11-02 12:26:22 -050085Compiler::Compiler(const ShaderCapsClass* caps, Flags flags)
John Stilesb30151e2021-01-11 16:13:08 -050086 : fContext(std::make_shared<Context>(/*errors=*/*this))
Brian Osman0006ad02020-11-18 15:38:39 -050087 , fCaps(caps)
John Stiles7b920442020-12-17 10:43:41 -050088 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -050089 , fFlags(flags)
90 , fErrorCount(0) {
91 SkASSERT(fCaps);
John Stiles7c3515b2020-10-16 18:38:39 -040092 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050093 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesb30151e2021-01-11 16:13:08 -050094 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), fCaps);
ethannicholasb3058bd2016-07-01 08:22:01 -070095
John Stiles54e7c052021-01-11 14:22:36 -050096#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -070097
Brian Osmanb06301e2020-11-06 11:45:36 -050098 const SkSL::Symbol* rootTypes[] = {
99 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500100
Brian Osmanb06301e2020-11-06 11:45:36 -0500101 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
102 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
103 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500104 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500105
Brian Osmanc0f2b642020-12-22 13:35:55 -0500106 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500107 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500108
Brian Osmanc63f4312020-12-23 11:44:14 -0500109 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700110
Brian Osman20fad322020-12-23 12:42:33 -0500111 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
112 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500113
114 TYPE(FragmentProcessor),
115 };
116
117 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500118 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
119 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
120 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
121 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
122 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
123
124 TYPE(GenUType), TYPE(UVec),
125 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
126
Brian Osmanc0f2b642020-12-22 13:35:55 -0500127 TYPE(Float2x3), TYPE(Float2x4),
128 TYPE(Float3x2), TYPE(Float3x4),
129 TYPE(Float4x2), TYPE(Float4x3),
130
Brian Osmanc63f4312020-12-23 11:44:14 -0500131 TYPE(Half2x3), TYPE(Half2x4),
132 TYPE(Half3x2), TYPE(Half3x4),
133 TYPE(Half4x2), TYPE(Half4x3),
134
Brian Osmanc0f2b642020-12-22 13:35:55 -0500135 TYPE(Mat), TYPE(HMat),
136
Brian Osmanb06301e2020-11-06 11:45:36 -0500137 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
138 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500139 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500140
141 TYPE(ISampler2D),
142 TYPE(Image2D), TYPE(IImage2D),
143 TYPE(SubpassInput), TYPE(SubpassInputMS),
144
Brian Osmanb06301e2020-11-06 11:45:36 -0500145 TYPE(Sampler),
146 TYPE(Texture2D),
147 };
148
149 for (const SkSL::Symbol* type : rootTypes) {
150 fRootSymbolTable->addWithoutOwnership(type);
151 }
152 for (const SkSL::Symbol* type : privateTypes) {
153 fPrivateSymbolTable->addWithoutOwnership(type);
154 }
155
156#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700157
Brian Osman3887a012020-09-30 13:22:27 -0400158 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
159 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500160 fPrivateSymbolTable->add(
161 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500162 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500163 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500164 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500165 /*builtin=*/false,
166 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500167
Brian Osman3d87e9f2020-10-08 11:50:22 -0400168 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500169 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700170}
171
John Stilesdd13dba2020-10-29 10:45:34 -0400172Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700173
Brian Osman56269982020-11-20 12:38:07 -0500174const ParsedModule& Compiler::loadGPUModule() {
175 if (!fGPUModule.fSymbols) {
176 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
177 }
178 return fGPUModule;
179}
180
181const ParsedModule& Compiler::loadFragmentModule() {
182 if (!fFragmentModule.fSymbols) {
183 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag),
184 this->loadGPUModule());
185 }
186 return fFragmentModule;
187}
188
189const ParsedModule& Compiler::loadVertexModule() {
190 if (!fVertexModule.fSymbols) {
191 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert),
192 this->loadGPUModule());
193 }
194 return fVertexModule;
195}
196
Brian Osman88cda172020-10-09 12:05:16 -0400197const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400198 if (!fGeometryModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500199 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom),
200 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400201 }
Brian Osman88cda172020-10-09 12:05:16 -0400202 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400203}
204
Brian Osman88cda172020-10-09 12:05:16 -0400205const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400206 if (!fFPModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500207 fFPModule = this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp),
208 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400209 }
Brian Osman88cda172020-10-09 12:05:16 -0400210 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400211}
212
Brian Osmanb06301e2020-11-06 11:45:36 -0500213const ParsedModule& Compiler::loadPublicModule() {
214 if (!fPublicModule.fSymbols) {
215 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
216 }
217 return fPublicModule;
218}
219
Brian Osman91946752020-12-21 13:20:40 -0500220const ParsedModule& Compiler::loadRuntimeEffectModule() {
221 if (!fRuntimeEffectModule.fSymbols) {
222 fRuntimeEffectModule = this->parseModule(Program::kRuntimeEffect_Kind, MODULE_DATA(runtime),
223 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400224
Brian Osman91946752020-12-21 13:20:40 -0500225 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500226 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400227
John Stiles54e7c052021-01-11 14:22:36 -0500228 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
229 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
230 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400231
John Stiles54e7c052021-01-11 14:22:36 -0500232 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
233 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
234 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400235
John Stiles54e7c052021-01-11 14:22:36 -0500236 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
237 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
238 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400239
John Stiles54e7c052021-01-11 14:22:36 -0500240 fRuntimeEffectModule.fSymbols->addAlias("mat2x2", fContext->fTypes.fFloat2x2.get());
241 fRuntimeEffectModule.fSymbols->addAlias("mat2x3", fContext->fTypes.fFloat2x3.get());
242 fRuntimeEffectModule.fSymbols->addAlias("mat2x4", fContext->fTypes.fFloat2x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400243
John Stiles54e7c052021-01-11 14:22:36 -0500244 fRuntimeEffectModule.fSymbols->addAlias("mat3x2", fContext->fTypes.fFloat3x2.get());
245 fRuntimeEffectModule.fSymbols->addAlias("mat3x3", fContext->fTypes.fFloat3x3.get());
246 fRuntimeEffectModule.fSymbols->addAlias("mat3x4", fContext->fTypes.fFloat3x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400247
John Stiles54e7c052021-01-11 14:22:36 -0500248 fRuntimeEffectModule.fSymbols->addAlias("mat4x2", fContext->fTypes.fFloat4x2.get());
249 fRuntimeEffectModule.fSymbols->addAlias("mat4x3", fContext->fTypes.fFloat4x3.get());
250 fRuntimeEffectModule.fSymbols->addAlias("mat4x4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400251 }
Brian Osman91946752020-12-21 13:20:40 -0500252 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400253}
254
Brian Osman88cda172020-10-09 12:05:16 -0400255const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
256 switch (kind) {
Brian Osman91946752020-12-21 13:20:40 -0500257 case Program::kVertex_Kind: return this->loadVertexModule(); break;
258 case Program::kFragment_Kind: return this->loadFragmentModule(); break;
259 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
260 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
261 case Program::kRuntimeEffect_Kind: return this->loadRuntimeEffectModule(); break;
Brian Osmance750362021-01-21 16:33:06 -0500262 case Program::kGeneric_Kind: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400263 }
264 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400265}
266
Brian Osman3d87e9f2020-10-08 11:50:22 -0400267LoadedModule Compiler::loadModule(Program::Kind kind,
268 ModuleData data,
269 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400270 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500271 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
272 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
273 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
274 // like samplers or textures. Today, 'Private' does contain the union of all known types,
275 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
276 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
277 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400278 }
279
280#if defined(SKSL_STANDALONE)
281 SkASSERT(data.fPath);
282 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400283 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
284 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400285 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400286 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400287 abort();
288 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400289 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400290 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400291 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400292 SkASSERT(fIRGenerator->fCanInline);
293 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400294 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500295 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500296 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500297 /*isBuiltinCode=*/true, source->c_str(), source->length(),
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500298 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400299 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500300 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400301 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400302 if (this->fErrorCount) {
303 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400304 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400305 }
Brian Osman88cda172020-10-09 12:05:16 -0400306 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400307#else
308 SkASSERT(data.fData && (data.fSize != 0));
309 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
310 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500311 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400312 fModifiers.push_back(fIRGenerator->releaseModifiers());
313#endif
314
315 return module;
316}
317
318ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500319 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
320 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400321
322 // For modules that just declare (but don't define) intrinsic functions, there will be no new
323 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500324 if (module.fElements.empty()) {
325 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400326 }
327
328 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
329
330 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
331 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500332 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400333 switch (element->kind()) {
334 case ProgramElement::Kind::kFunction: {
335 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400336 SkASSERT(f.declaration().isBuiltin());
337 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400338 break;
339 }
John Stiles569249b2020-11-03 12:18:22 -0500340 case ProgramElement::Kind::kFunctionPrototype: {
341 // These are already in the symbol table.
342 break;
343 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400344 case ProgramElement::Kind::kEnum: {
345 const Enum& e = element->as<Enum>();
346 SkASSERT(e.isBuiltin());
347 intrinsics->insertOrDie(e.typeName(), std::move(element));
348 break;
349 }
350 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400351 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
352 const Variable& var = global.declaration()->as<VarDeclaration>().var();
353 SkASSERT(var.isBuiltin());
354 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400355 break;
356 }
357 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400358 const Variable& var = element->as<InterfaceBlock>().variable();
359 SkASSERT(var.isBuiltin());
360 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400361 break;
362 }
363 default:
364 printf("Unsupported element: %s\n", element->description().c_str());
365 SkASSERT(false);
366 break;
367 }
368 }
369
Brian Osman0006ad02020-11-18 15:38:39 -0500370 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400371}
372
John Stilese6150002020-10-05 12:03:53 -0400373void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700374 BasicBlock& block = cfg->fBlocks[blockId];
375
376 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500377 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700378 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500379 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700380 }
381
382 // propagate definitions to exits
383 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400384 if (exitId == blockId) {
385 continue;
386 }
ethannicholas22f939e2016-10-13 13:25:34 -0700387 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500388 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400389 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
390 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400391 // exit has no definition for it, just copy it and reprocess exit block
392 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500393 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700394 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500395 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400396 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700397 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400398 // definition has changed, merge and reprocess the exit block
399 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500400 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400401 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500402 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400403 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500404 }
ethannicholas22f939e2016-10-13 13:25:34 -0700405 }
406 }
John Stiles65b48272020-12-22 17:18:34 -0500407 }
ethannicholas22f939e2016-10-13 13:25:34 -0700408 }
409}
410
Ethan Nicholascb670962017-04-20 19:31:52 -0400411/**
412 * Returns true if assigning to this lvalue has no effect.
413 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400414static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400415 switch (lvalue.kind()) {
416 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400417 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400418 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400419 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400420 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400421 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400422 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400423 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400424 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400425 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400426 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400427 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400428 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400429 return !t.test()->hasSideEffects() &&
430 is_dead(*t.ifTrue(), usage) &&
431 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500432 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400433 default:
John Stileseada7bc2021-02-02 16:29:32 -0500434 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500435 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400436 }
437}
ethannicholas22f939e2016-10-13 13:25:34 -0700438
Ethan Nicholascb670962017-04-20 19:31:52 -0400439/**
440 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
441 * to a dead target and lack of side effects on the left hand side.
442 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400443static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Brian Osman00185012021-02-04 16:07:11 -0500444 if (!Operators::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400445 return false;
446 }
John Stiles2d4f9592020-10-30 10:29:12 -0400447 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400448}
449
450void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500451 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400452
453 // We set bits in the "processed" set after a block has been scanned.
454 SkBitSet processedSet(cfg->fBlocks.size());
455 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
456 processedSet.set(*blockId);
457 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700458 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400459}
460
461/**
462 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
463 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
464 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
465 * need to be regenerated).
466 */
John Stilesafbf8992020-08-18 10:08:21 -0400467static bool try_replace_expression(BasicBlock* b,
468 std::vector<BasicBlock::Node>::iterator* iter,
469 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400470 std::unique_ptr<Expression>* target = (*iter)->expression();
471 if (!b->tryRemoveExpression(iter)) {
472 *target = std::move(*newExpression);
473 return false;
474 }
475 *target = std::move(*newExpression);
476 return b->tryInsertExpression(iter, target);
477}
478
479/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400480 * Returns true if the expression is a constant numeric literal with the specified value, or a
481 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400482 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400483template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400484static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400485 switch (expr.kind()) {
486 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400487 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400488
Ethan Nicholase6592142020-09-08 10:22:09 -0400489 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400490 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400491
Ethan Nicholase6592142020-09-08 10:22:09 -0400492 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400493 const Constructor& constructor = expr.as<Constructor>();
494 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400495 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400496 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400497 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500498 if (constructor.componentType().isFloat()) {
499 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400500 if (constructor.getFVecComponent(i) != value) {
501 return false;
502 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500503 }
504 return true;
505 } else if (constructor.componentType().isInteger()) {
506 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400507 if (constructor.getIVecComponent(i) != value) {
508 return false;
509 }
510 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500511 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400512 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500513 // Other types (e.g. boolean) might occur, but aren't supported here.
514 return false;
John Stiles9d944232020-08-19 09:56:49 -0400515
Ethan Nicholase6592142020-09-08 10:22:09 -0400516 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400517 SkASSERT(constructor.arguments().size() == 1);
518 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400519
520 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400521 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400522 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400523 }
524 return false;
525 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400526 default:
527 return false;
528 }
529}
530
531/**
532 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
533 * and CFG structures).
534 */
John Stilesafbf8992020-08-18 10:08:21 -0400535static void delete_left(BasicBlock* b,
536 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400537 Compiler::OptimizationContext* optimizationContext) {
538 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400539 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400540 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400541 Expression& left = *bin.left();
542 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400543 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400544 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400545 if (bin.getOperator() == Token::Kind::TK_EQ) {
546 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400547 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400548 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400549 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400550 // Remove references within LHS.
551 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400552 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400553 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400554 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400555 return;
556 }
557 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400558 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400559 return;
560 }
561 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400562 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400563 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400564 return;
565 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400566 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400567 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400568}
569
570/**
571 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
572 * CFG structures).
573 */
John Stilesafbf8992020-08-18 10:08:21 -0400574static void delete_right(BasicBlock* b,
575 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400576 Compiler::OptimizationContext* optimizationContext) {
577 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400578 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400579 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400580 std::unique_ptr<Expression>& leftPointer = bin.left();
581 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400582 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400583 // Remove references within RHS.
584 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400585 if (!b->tryRemoveExpressionBefore(iter, &right)) {
586 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400587 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400588 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400589 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400590 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400591 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400592 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400593 return;
594 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400595 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400596 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400597 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400598 return;
599 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400600 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400601 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400602}
603
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400604/**
605 * Constructs the specified type using a single argument.
606 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400607static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400608 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400609 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400610 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400611 return result;
612}
613
614/**
615 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
616 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
617 */
618static void vectorize(BasicBlock* b,
619 std::vector<BasicBlock::Node>::iterator* iter,
620 const Type& type,
621 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400622 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400623 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500624 SkASSERT(type.isVector());
625 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400626 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400627 std::unique_ptr<Expression>* target = (*iter)->expression();
628 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400629 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400630 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400631 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400632 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400633 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400634 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400635 }
636 }
637}
638
639/**
640 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
641 * left to yield vec<n>(x).
642 */
643static void vectorize_left(BasicBlock* b,
644 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400645 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400646 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400647 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400648 optimizationContext->fUsage->remove(bin.right().get());
649 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400650}
651
652/**
653 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
654 * right to yield vec<n>(y).
655 */
656static void vectorize_right(BasicBlock* b,
657 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400658 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400659 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400660 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400661 optimizationContext->fUsage->remove(bin.left().get());
662 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400663}
664
665// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400666static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400667 switch (expr.kind()) {
668 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400669 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400670 break;
671 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400672 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400673 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400674 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400675 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400676 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400677 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400678 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400679 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400680 break;
681 default:
John Stilesf57207b2021-02-02 17:50:34 -0500682 SK_ABORT("shouldn't be writing to this kind of expression\n");
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400683 break;
684 }
685}
686
Ethan Nicholascb670962017-04-20 19:31:52 -0400687void Compiler::simplifyExpression(DefinitionMap& definitions,
688 BasicBlock& b,
689 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400690 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400691 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400692 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500693
Ethan Nicholascb670962017-04-20 19:31:52 -0400694 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400695 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
696 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400697 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400698 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400699 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400700 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400701 // Remove references within 'expr', add references within 'optimized'
702 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400703 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400704 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400705 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400706 }
John Stiles70025e52020-09-28 16:08:58 -0400707 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400708 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400709 }
710 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400711 switch (expr->kind()) {
712 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400713 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400714 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400715 if (ref.refKind() != VariableReference::RefKind::kWrite &&
716 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500717 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400718 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
719 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000720 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400721 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400722 }
723 break;
724 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400725 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400726 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400727 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400728 // ternary has a constant test, replace it with either the true or
729 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400730 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400731 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400732 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400733 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400734 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400735 optimizationContext->fUpdated = true;
736 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400737 }
738 break;
739 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400740 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400741 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400742 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400743 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400744 break;
745 }
John Stiles2d4f9592020-10-30 10:29:12 -0400746 Expression& left = *bin->left();
747 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400748 const Type& leftType = left.type();
749 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400750 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500751 if ((!leftType.isScalar() && !leftType.isVector()) ||
752 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400753 break;
754 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400755 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400756 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400757 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500758 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400759 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400760 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400761 } else {
762 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400763 // 1 * float4(x) -> float4(x)
764 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400765 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400766 }
767 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400768 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500769 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400770 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400771 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400772 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400773 } else {
774 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400775 // float4(0) * x -> float4(0)
776 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400777 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400778 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500779 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400780 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400781 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400782 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500783 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400784 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400785 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400786 } else {
787 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400788 // float4(x) * 1 -> float4(x)
789 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400790 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400791 }
792 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400793 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500794 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400795 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400796 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400797 } else {
798 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400799 // x * float4(0) -> float4(0)
800 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400801 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400802 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500803 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400804 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400805 }
806 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400807 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400808 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500809 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400810 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400811 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400812 } else {
813 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400814 // 0 + float4(x) -> float4(x)
815 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400816 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400817 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400818 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500819 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400820 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400821 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400822 } else {
823 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400824 // float4(x) + 0 -> float4(x)
825 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400826 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400827 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400828 }
829 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400830 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400831 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500832 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400833 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400834 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400835 } else {
836 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400837 // float4(x) - 0 -> float4(x)
838 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400839 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400840 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400841 }
842 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400843 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400844 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500845 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400846 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400847 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400848 } else {
849 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400850 // float4(x) / 1 -> float4(x)
851 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400852 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400853 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400854 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500855 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400856 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400857 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400858 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400859 } else {
860 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400861 // float4(0) / x -> float4(0)
862 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400863 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400864 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500865 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400866 }
867 }
868 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400869 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400870 if (is_constant(right, 0)) {
871 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400872 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400873 }
874 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400875 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400876 if (is_constant(right, 0)) {
877 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400878 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400879 }
880 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400881 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400882 if (is_constant(right, 1)) {
883 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400884 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400885 }
886 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400887 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400888 if (is_constant(right, 1)) {
889 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400890 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400891 }
892 break;
893 default:
894 break;
895 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400896 break;
897 }
John Stilesf5c1d042020-11-21 23:26:07 -0500898 case Expression::Kind::kConstructor: {
899 // Find constructors embedded inside constructors and flatten them out where possible.
900 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
901 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
902 // Leave single-argument constructors alone, though. These might be casts or splats.
903 Constructor& c = expr->as<Constructor>();
904 if (c.type().columns() > 1) {
905 // Inspect each constructor argument to see if it's a candidate for flattening.
906 // Remember matched arguments in a bitfield, "argsToOptimize".
907 int argsToOptimize = 0;
908 int currBit = 1;
909 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
910 if (arg->is<Constructor>()) {
911 Constructor& inner = arg->as<Constructor>();
912 if (inner.arguments().size() > 1 &&
913 inner.type().componentType() == c.type().componentType()) {
914 argsToOptimize |= currBit;
915 }
916 }
917 currBit <<= 1;
918 }
919 if (argsToOptimize) {
920 // We found at least one argument that could be flattened out. Re-walk the
921 // constructor args and flatten the candidates we found during our initial pass.
922 ExpressionArray flattened;
923 flattened.reserve_back(c.type().columns());
924 currBit = 1;
925 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
926 if (argsToOptimize & currBit) {
927 Constructor& inner = arg->as<Constructor>();
928 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
929 flattened.push_back(innerArg->clone());
930 }
931 } else {
932 flattened.push_back(arg->clone());
933 }
934 currBit <<= 1;
935 }
936 auto optimized = std::unique_ptr<Expression>(
937 new Constructor(c.fOffset, &c.type(), std::move(flattened)));
938 // No fUsage change; no references have been added or removed anywhere.
939 optimizationContext->fUpdated = true;
940 if (!try_replace_expression(&b, iter, &optimized)) {
941 optimizationContext->fNeedsRescan = true;
942 return;
943 }
944 SkASSERT((*iter)->isExpression());
945 break;
946 }
947 }
948 break;
949 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400950 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400951 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500952 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400953 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400954 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400955 for (int i = 0; i < (int) s.components().size(); ++i) {
956 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400957 identity = false;
958 break;
959 }
960 }
961 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400962 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400963 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400964 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400965 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400966 return;
967 }
John Stiles70025e52020-09-28 16:08:58 -0400968 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400969 break;
970 }
971 }
John Stiles108bbe22020-11-18 11:10:38 -0500972 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
973 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400974 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400975 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400976 for (int c : s.components()) {
977 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400978 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400979 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400980 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500981 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -0500982 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -0500983 try_replace_expression(&b, iter, &replacement);
984 optimizationContext->fUpdated = true;
985 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -0500986 break;
987 }
988 // Optimize swizzles of constructors.
989 if (s.base()->is<Constructor>()) {
990 Constructor& base = s.base()->as<Constructor>();
991 std::unique_ptr<Expression> replacement;
992 const Type& componentType = base.type().componentType();
993 int swizzleSize = s.components().size();
994
995 // The IR generator has already converted any zero/one swizzle components into
996 // constructors containing zero/one args. Confirm that this is true by checking that
997 // our swizzle components are all `xyzw` (values 0 through 3).
998 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
999 [](int8_t c) { return c >= 0 && c <= 3; }));
1000
John Stiles9aeed132020-11-24 17:36:06 -05001001 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001002 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1003 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001004 const Expression& argument = *base.arguments().front();
1005 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1006 /*rows=*/1);
1007 replacement = Constructor::SimplifyConversion(constructorType, argument);
1008 if (!replacement) {
1009 ExpressionArray newArgs;
1010 newArgs.push_back(argument.clone());
1011 replacement = std::make_unique<Constructor>(base.fOffset, &constructorType,
1012 std::move(newArgs));
1013 }
John Stiles108bbe22020-11-18 11:10:38 -05001014
John Stilesa60ac0c2020-12-22 08:59:51 -05001015 // We're replacing an expression with a cloned version; we'll need a rescan.
1016 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1017 // reference counts.
1018 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001019 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001020 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001021 break;
1022 }
1023
John Stiles0777ac42020-11-19 11:06:47 -05001024 // Swizzles can duplicate some elements and discard others, e.g.
1025 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1026 // - Expressions with side effects need to occur exactly once, even if they
1027 // would otherwise be swizzle-eliminated
1028 // - Non-trivial expressions should not be repeated, but elimination is OK.
1029 //
1030 // Look up the argument for the constructor at each index. This is typically simple
1031 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1032 // seems. This example would result in:
1033 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1034 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1035 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1036 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1037 struct ConstructorArgMap {
1038 int8_t fArgIndex;
1039 int8_t fComponent;
1040 };
1041
1042 int numConstructorArgs = base.type().columns();
1043 ConstructorArgMap argMap[4] = {};
1044 int writeIdx = 0;
1045 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1046 const Expression& expr = *base.arguments()[argIdx];
1047 int argWidth = expr.type().columns();
1048 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1049 argMap[writeIdx].fArgIndex = argIdx;
1050 argMap[writeIdx].fComponent = componentIdx;
1051 ++writeIdx;
1052 }
1053 }
1054 SkASSERT(writeIdx == numConstructorArgs);
1055
1056 // Count up the number of times each constructor argument is used by the
1057 // swizzle.
1058 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1059 // - bar.yz is referenced 3 times, by `.x_xy`
1060 // - half(foo) is referenced 1 time, by `._w__`
1061 int8_t exprUsed[4] = {};
1062 for (int c : s.components()) {
1063 exprUsed[argMap[c].fArgIndex]++;
1064 }
1065
1066 bool safeToOptimize = true;
1067 for (int index = 0; index < numConstructorArgs; ++index) {
1068 int8_t constructorArgIndex = argMap[index].fArgIndex;
1069 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1070
1071 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001072 if (exprUsed[constructorArgIndex] > 1 &&
1073 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001074 safeToOptimize = false;
1075 break;
1076 }
1077 // Check that side-effect-bearing expressions are swizzled in exactly once.
1078 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1079 safeToOptimize = false;
1080 break;
1081 }
1082 }
1083
1084 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001085 struct ReorderedArgument {
1086 int8_t fArgIndex;
1087 ComponentArray fComponents;
1088 };
1089 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001090 for (int c : s.components()) {
1091 const ConstructorArgMap& argument = argMap[c];
1092 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1093
John Stiles9aeed132020-11-24 17:36:06 -05001094 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001095 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001096 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001097 reorderedArgs.push_back({argument.fArgIndex,
1098 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001099 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001100 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001101 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001102 if (reorderedArgs.empty() ||
1103 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1104 // This can't be combined with the previous argument. Add a new one.
1105 reorderedArgs.push_back({argument.fArgIndex,
1106 ComponentArray{argument.fComponent}});
1107 } else {
1108 // Since we know this argument uses components, it should already
1109 // have at least one component set.
1110 SkASSERT(!reorderedArgs.back().fComponents.empty());
1111 // Build up the current argument with one more component.
1112 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1113 }
John Stiles0777ac42020-11-19 11:06:47 -05001114 }
1115 }
John Stilesd9076cb2020-11-19 12:18:36 -05001116
1117 // Convert our reordered argument list to an actual array of expressions, with
1118 // the new order and any new inner swizzles that need to be applied. Note that
1119 // we expect followup passes to clean up the inner swizzles.
1120 ExpressionArray newArgs;
1121 newArgs.reserve_back(swizzleSize);
1122 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1123 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1124 if (reorderedArg.fComponents.empty()) {
1125 newArgs.push_back(baseArg.clone());
1126 } else {
1127 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1128 reorderedArg.fComponents));
1129 }
1130 }
1131
1132 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001133 replacement = std::make_unique<Constructor>(
1134 base.fOffset,
1135 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1136 std::move(newArgs));
1137
John Stilesa60ac0c2020-12-22 08:59:51 -05001138 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001139 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001140
1141 // We're replacing an expression with a cloned version; we'll need a rescan.
1142 try_replace_expression(&b, iter, &replacement);
1143 optimizationContext->fUpdated = true;
1144 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001145 }
John Stiles108bbe22020-11-18 11:10:38 -05001146 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001147 }
John Stiles30212b72020-06-11 17:55:07 -04001148 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001149 }
1150 default:
1151 break;
1152 }
1153}
1154
John Stiles92219b42020-06-15 12:32:24 -04001155// Returns true if this statement could potentially execute a break at the current level. We ignore
1156// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001157static bool contains_conditional_break(Statement& stmt) {
1158 class ContainsConditionalBreak : public ProgramVisitor {
1159 public:
1160 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001161 switch (stmt.kind()) {
1162 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001163 return this->INHERITED::visitStatement(stmt);
1164
Ethan Nicholase6592142020-09-08 10:22:09 -04001165 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001166 return fInConditional > 0;
1167
Ethan Nicholase6592142020-09-08 10:22:09 -04001168 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001169 ++fInConditional;
1170 bool result = this->INHERITED::visitStatement(stmt);
1171 --fInConditional;
1172 return result;
1173 }
1174
1175 default:
1176 return false;
1177 }
1178 }
1179
1180 int fInConditional = 0;
1181 using INHERITED = ProgramVisitor;
1182 };
1183
1184 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001185}
1186
Ethan Nicholas5005a222018-08-24 13:06:27 -04001187// returns true if this statement definitely executes a break at the current level (we ignore
1188// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001189static bool contains_unconditional_break(Statement& stmt) {
1190 class ContainsUnconditionalBreak : public ProgramVisitor {
1191 public:
1192 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001193 switch (stmt.kind()) {
1194 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001195 return this->INHERITED::visitStatement(stmt);
1196
Ethan Nicholase6592142020-09-08 10:22:09 -04001197 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001198 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001199
1200 default:
1201 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001202 }
John Stilesb92641c2020-08-31 18:09:01 -04001203 }
John Stiles92219b42020-06-15 12:32:24 -04001204
John Stilesb92641c2020-08-31 18:09:01 -04001205 using INHERITED = ProgramVisitor;
1206 };
John Stiles92219b42020-06-15 12:32:24 -04001207
John Stilesb92641c2020-08-31 18:09:01 -04001208 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001209}
1210
John Stiles8f2a0cf2020-10-13 12:48:21 -04001211static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001212 switch (stmt->kind()) {
1213 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001214 // Recurse into the block.
1215 Block& block = static_cast<Block&>(*stmt);
1216
John Stiles8f2a0cf2020-10-13 12:48:21 -04001217 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001218 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001219 for (std::unique_ptr<Statement>& stmt : block.children()) {
1220 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001221 }
John Stiles92219b42020-06-15 12:32:24 -04001222
1223 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001224 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001225 break;
John Stiles92219b42020-06-15 12:32:24 -04001226 }
1227
Ethan Nicholase6592142020-09-08 10:22:09 -04001228 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001229 // Do not append a break to the target.
1230 break;
1231
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001232 default:
John Stiles92219b42020-06-15 12:32:24 -04001233 // Append normal statements to the target.
1234 target->push_back(std::move(stmt));
1235 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001236 }
1237}
1238
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001239// Returns a block containing all of the statements that will be run if the given case matches
1240// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1241// broken by this call and must then be discarded).
1242// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1243// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001244static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1245 SwitchCase* caseToCapture) {
1246 // We have to be careful to not move any of the pointers until after we're sure we're going to
1247 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1248 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001249 auto iter = switchStatement->cases().begin();
1250 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001251 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001252 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001253 }
John Stiles92219b42020-06-15 12:32:24 -04001254 }
1255
1256 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1257 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1258 // statements that we can use for simplification.
1259 auto startIter = iter;
1260 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001261 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001262 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001263 if (contains_conditional_break(*stmt)) {
1264 // We can't reduce switch-cases to a block when they have conditional breaks.
1265 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001266 }
John Stiles92219b42020-06-15 12:32:24 -04001267
1268 if (contains_unconditional_break(*stmt)) {
1269 // We found an unconditional break. We can use this block, but we need to strip
1270 // out the break statement.
1271 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001272 break;
1273 }
1274 }
John Stiles92219b42020-06-15 12:32:24 -04001275
1276 if (unconditionalBreakStmt != nullptr) {
1277 break;
1278 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001279 }
John Stiles92219b42020-06-15 12:32:24 -04001280
1281 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1282 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001283 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001284
1285 // We can move over most of the statements as-is.
1286 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001287 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001288 caseStmts.push_back(std::move(stmt));
1289 }
1290 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001291 }
John Stiles92219b42020-06-15 12:32:24 -04001292
1293 // If we found an unconditional break at the end, we need to move what we can while avoiding
1294 // that break.
1295 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001296 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001297 if (stmt.get() == unconditionalBreakStmt) {
1298 move_all_but_break(stmt, &caseStmts);
1299 unconditionalBreakStmt = nullptr;
1300 break;
1301 }
1302
1303 caseStmts.push_back(std::move(stmt));
1304 }
1305 }
1306
1307 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1308
1309 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001310 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001311}
1312
Ethan Nicholascb670962017-04-20 19:31:52 -04001313void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001314 BasicBlock& b,
1315 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001316 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001317 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001318 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001319 switch (stmt->kind()) {
1320 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001321 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001322 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001323 (!varDecl.value() ||
1324 !varDecl.value()->hasSideEffects())) {
1325 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001326 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001327 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001328 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001329 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001330 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001331 // There can still be (soon to be removed) references to the variable at this point.
1332 // Allowing the VarDeclaration to be destroyed here will break those variable's
1333 // initialValue()s, so we hang on to them until optimization is finished.
1334 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1335 usage);
1336 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001337 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001338 }
1339 break;
1340 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001341 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001342 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001343 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001344 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001345 if (i.test()->as<BoolLiteral>().value()) {
1346 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001347 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001348 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001349 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001350 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001351 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001352 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001353 }
1354 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001355 optimizationContext->fUpdated = true;
1356 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001357 break;
1358 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001359 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001360 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001361 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001362 optimizationContext->fUpdated = true;
1363 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001364 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001365 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001366 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001367 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001368 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001369 (*iter)->setStatement(
1370 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001371 } else {
1372 // no if, no else, no test side effects, kill the whole if
1373 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001374 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001375 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001376 optimizationContext->fUpdated = true;
1377 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001378 }
1379 break;
1380 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001381 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001382 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001383 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001384 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001385 // switch is constant, replace it with the case that matches
1386 bool found = false;
1387 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001388 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1389 if (!c->value()) {
1390 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001391 continue;
1392 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001393 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001394 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001395 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001396 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001397 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001398 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001399 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001400 break;
1401 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001402 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1403 optimizationContext->fSilences.find(&s) ==
1404 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001405 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001406 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001407 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001408 }
1409 return; // can't simplify
1410 }
1411 }
1412 }
1413 if (!found) {
1414 // no matching case. use default if it exists, or kill the whole thing
1415 if (defaultCase) {
1416 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1417 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001418 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001419 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001420 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1421 optimizationContext->fSilences.find(&s) ==
1422 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001423 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001424 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001425 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001426 }
1427 return; // can't simplify
1428 }
1429 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001430 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001431 }
1432 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001433 optimizationContext->fUpdated = true;
1434 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001435 }
1436 break;
1437 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001438 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001439 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001440 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001441 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001442 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001443 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001444 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001445 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001446 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001447 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001448 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001449 }
1450 break;
1451 }
1452 default:
1453 break;
1454 }
1455}
1456
Brian Osman010ce6a2020-10-19 16:34:10 -04001457bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001458 bool madeChanges = false;
1459
Ethan Nicholascb670962017-04-20 19:31:52 -04001460 CFG cfg = CFGGenerator().getCFG(f);
1461 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001462
1463 // check for unreachable code
1464 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001465 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001466 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
John Stiles0cc193a2020-09-09 09:39:34 -04001467 const BasicBlock::Node& node = block.fNodes[0];
John Stilesc1129322021-02-03 10:13:42 -05001468 int offset = node.isStatement() ? (*node.statement())->fOffset
1469 : (*node.expression())->fOffset;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001470 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001471 }
1472 }
1473 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001474 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001475 }
1476
Ethan Nicholascb670962017-04-20 19:31:52 -04001477 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001478 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001479 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001480 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001481 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001482 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001483 cfg = CFGGenerator().getCFG(f);
1484 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001485 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001486 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001487
John Stiles7d3f0892020-11-03 11:35:01 -05001488 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001489 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001490
1491 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1492 if (eliminatedBlockIds.test(blockId)) {
1493 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1494 optimizationContext.fUpdated = true;
1495 optimizationContext.fNeedsRescan = true;
1496 break;
1497 }
1498
1499 BasicBlock& b = cfg.fBlocks[blockId];
1500 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001501 // Block was reachable before optimization, but has since become unreachable. In
1502 // addition to being dead code, it's broken - since control flow can't reach it, no
1503 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001504 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001505 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001506 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001507 // Eliminating a node runs the risk of eliminating that node's exits as
1508 // well. Keep track of this and do a rescan if we are about to access one
1509 // of these.
1510 for (BlockId id : b.fExits) {
1511 eliminatedBlockIds.set(id);
1512 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001513 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001514 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001515 }
1516 }
1517 continue;
1518 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001519 DefinitionMap definitions = b.fBefore;
1520
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001521 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1522 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001523 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001524 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001525 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001526 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001527 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001528 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001529 break;
1530 }
John Stilese8a24922021-02-08 17:54:08 -05001531 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001532 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001533
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001534 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001535 break;
1536 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001537 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001538 madeChanges |= optimizationContext.fUpdated;
1539 } while (optimizationContext.fUpdated);
1540 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001541
Ethan Nicholas91a10532017-06-22 11:24:38 -04001542 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001543 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001544 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1545 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001546 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001547 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001548 switch (s.kind()) {
1549 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001550 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001551 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001552 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001553 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001554 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001555 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001556 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001557 if (s.as<SwitchStatement>().isStatic() &&
1558 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1559 optimizationContext.fSilences.find(&s) ==
1560 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001561 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001562 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001563 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001564 break;
1565 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001566 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001567 break;
1568 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001569 } else {
1570 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001571 }
1572 }
1573 }
1574
ethannicholas22f939e2016-10-13 13:25:34 -07001575 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001576 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001577 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001578 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001579 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001580 }
1581 }
John Stiles0cc193a2020-09-09 09:39:34 -04001582
1583 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001584}
1585
Brian Osman32d53552020-09-23 13:55:20 -04001586std::unique_ptr<Program> Compiler::convertProgram(
1587 Program::Kind kind,
1588 String text,
1589 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001590 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
1591 SkASSERT(!externalFunctions || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001592
Brian Osman0006ad02020-11-18 15:38:39 -05001593 // Loading and optimizing our base module might reset the inliner, so do that first,
1594 // *then* configure the inliner with the settings for this program.
1595 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1596
ethannicholasb3058bd2016-07-01 08:22:01 -07001597 fErrorText = "";
1598 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001599 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001600
1601 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001602 std::unique_ptr<String> textPtr(new String(std::move(text)));
1603 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001604
John Stiles5c7bb322020-10-22 11:09:15 -04001605 // Enable node pooling while converting and optimizing the program for a performance boost.
1606 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001607 std::unique_ptr<Pool> pool;
1608 if (fCaps->useNodePools()) {
1609 pool = Pool::Create();
1610 pool->attachToThread();
1611 }
Brian Osman0006ad02020-11-18 15:38:39 -05001612 IRGenerator::IRBundle ir =
1613 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001614 textPtr->c_str(), textPtr->size(), externalFunctions);
John Stiles5c7bb322020-10-22 11:09:15 -04001615 auto program = std::make_unique<Program>(kind,
1616 std::move(textPtr),
1617 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001618 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001619 fContext,
1620 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001621 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001622 std::move(ir.fModifiers),
1623 std::move(ir.fSymbolTable),
1624 std::move(pool),
1625 ir.fInputs);
1626 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001627 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001628 // Do not return programs that failed to compile.
1629 } else if (settings.fOptimize && !this->optimize(*program)) {
1630 // Do not return programs that failed to optimize.
1631 } else {
1632 // We have a successful program!
1633 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001634 }
John Stiles5c7bb322020-10-22 11:09:15 -04001635
Brian Osman28f702c2021-02-02 11:52:07 -05001636 if (program->fPool) {
1637 program->fPool->detachFromThread();
1638 }
John Stiles5c7bb322020-10-22 11:09:15 -04001639 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001640}
1641
Brian Osman0006ad02020-11-18 15:38:39 -05001642bool Compiler::optimize(LoadedModule& module) {
1643 SkASSERT(!fErrorCount);
1644 Program::Settings settings;
1645 fIRGenerator->fKind = module.fKind;
1646 fIRGenerator->fSettings = &settings;
1647 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1648
1649 fInliner.reset(fModifiers.back().get(), &settings);
1650
1651 while (fErrorCount == 0) {
1652 bool madeChanges = false;
1653
1654 // Scan and optimize based on the control-flow graph for each function.
1655 for (const auto& element : module.fElements) {
1656 if (element->is<FunctionDefinition>()) {
1657 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1658 }
1659 }
1660
1661 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001662 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001663
1664 if (!madeChanges) {
1665 break;
1666 }
1667 }
1668 return fErrorCount == 0;
1669}
1670
Ethan Nicholas00543112018-07-31 09:44:36 -04001671bool Compiler::optimize(Program& program) {
1672 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001673 fIRGenerator->fKind = program.fKind;
1674 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001675 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001676
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001677 while (fErrorCount == 0) {
1678 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001679
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001680 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001681 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001682 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001683 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001684 }
1685 }
1686
1687 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001688 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001689
1690 // Remove dead functions. We wait until after analysis so that we still report errors,
1691 // even in unused code.
1692 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001693 auto isDeadFunction = [&](const ProgramElement* element) {
1694 if (!element->is<FunctionDefinition>()) {
1695 return false;
1696 }
1697 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1698 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1699 usage->remove(*element);
1700 madeChanges = true;
1701 return true;
1702 }
1703 return false;
1704 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001705 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001706 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001707 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001708 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001709 }),
1710 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001711 program.fSharedElements.erase(
1712 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1713 isDeadFunction),
1714 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001715 }
1716
1717 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001718 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001719 auto isDeadVariable = [&](const ProgramElement* element) {
1720 if (!element->is<GlobalVarDeclaration>()) {
1721 return false;
1722 }
1723 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1724 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1725 if (usage->isDead(varDecl.var())) {
1726 madeChanges = true;
1727 return true;
1728 }
1729 return false;
1730 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001731 program.fElements.erase(
1732 std::remove_if(program.fElements.begin(), program.fElements.end(),
1733 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001734 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001735 }),
1736 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001737 program.fSharedElements.erase(
1738 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1739 isDeadVariable),
1740 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001741 }
John Stiles73a6bff2020-09-09 13:40:37 -04001742
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001743 if (!madeChanges) {
1744 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001745 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001746 }
1747 return fErrorCount == 0;
1748}
1749
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001750#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1751
Ethan Nicholas00543112018-07-31 09:44:36 -04001752bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001753#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001754 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001755 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001756 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001757 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001758 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001759 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001760 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001761 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001762 String errors;
1763 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1764 const char* m) {
1765 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001766 };
1767 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001768
1769 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1770 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1771 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1772 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1773
1774 if (!result) {
1775#if defined(SKSL_STANDALONE)
1776 // Convert the string-stream to a SPIR-V disassembly.
1777 std::string disassembly;
1778 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1779 errors.append(disassembly);
1780 }
1781 this->error(-1, errors);
1782#else
1783 SkDEBUGFAILF("%s", errors.c_str());
1784#endif
1785 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001786 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001787 }
1788#else
Brian Osman88cda172020-10-09 12:05:16 -04001789 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001790 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001791 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001792#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001793 return result;
1794}
1795
Ethan Nicholas00543112018-07-31 09:44:36 -04001796bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001797 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001798 bool result = this->toSPIRV(program, buffer);
1799 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001800 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001801 }
1802 return result;
1803}
1804
Ethan Nicholas00543112018-07-31 09:44:36 -04001805bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001806 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001807 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001808 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001809 return result;
1810}
1811
Ethan Nicholas00543112018-07-31 09:44:36 -04001812bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001813 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001814 bool result = this->toGLSL(program, buffer);
1815 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001816 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001817 }
1818 return result;
1819}
1820
Brian Osmanc0243912020-02-19 15:35:26 -05001821bool Compiler::toHLSL(Program& program, String* out) {
1822 String spirv;
1823 if (!this->toSPIRV(program, &spirv)) {
1824 return false;
1825 }
1826
1827 return SPIRVtoHLSL(spirv, out);
1828}
1829
Ethan Nicholas00543112018-07-31 09:44:36 -04001830bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001831 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001832 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001833 return result;
1834}
1835
Ethan Nicholas00543112018-07-31 09:44:36 -04001836bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001837 StringStream buffer;
1838 bool result = this->toMetal(program, buffer);
1839 if (result) {
1840 *out = buffer.str();
1841 }
1842 return result;
1843}
1844
Greg Daniela28ea672020-09-25 11:12:56 -04001845#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001846bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001847 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001848 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001849 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001850 return result;
1851}
1852
Ethan Nicholas00543112018-07-31 09:44:36 -04001853bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001854 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001855 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001856 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001857 return result;
1858}
Greg Daniela28ea672020-09-25 11:12:56 -04001859#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001860
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001861#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001862
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001863Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001864 if (fSource && offset >= 0) {
1865 int line = 1;
1866 int column = 1;
1867 for (int i = 0; i < offset; i++) {
1868 if ((*fSource)[i] == '\n') {
1869 ++line;
1870 column = 1;
1871 }
1872 else {
1873 ++column;
1874 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001875 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001876 return Position(line, column);
1877 } else {
1878 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001879 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001880}
1881
1882void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001883 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001884 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001885 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001886 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001887}
1888
John Stiles8d3642e2021-01-22 09:50:04 -05001889void Compiler::setErrorCount(int c) {
1890 if (c < fErrorCount) {
1891 fErrorText.resize(fErrorTextLength[c]);
1892 fErrorTextLength.resize(c);
1893 fErrorCount = c;
1894 }
1895}
1896
Ethan Nicholas95046142021-01-07 10:57:27 -05001897String Compiler::errorText(bool showCount) {
1898 if (showCount) {
1899 this->writeErrorCount();
1900 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001901 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001902 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001903 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001904 return result;
1905}
1906
1907void Compiler::writeErrorCount() {
1908 if (fErrorCount) {
1909 fErrorText += to_string(fErrorCount) + " error";
1910 if (fErrorCount > 1) {
1911 fErrorText += "s";
1912 }
1913 fErrorText += "\n";
1914 }
1915}
1916
John Stilesa6841be2020-08-06 14:11:56 -04001917} // namespace SkSL